powered by TinkerSpace.in
Join free
TINKERPY · LANGUAGE REFERENCE

TinkerPy language reference

TinkerPy is a simplified, Python-based coding language for kids, made for the TinkerPy Mega and Mini boards. This page has everything: the pins, the rules, every library and function with examples, and complete projects.

Contents Part 2 — The TinkerPy Mega board and its pins Part 3 — Program structure and language rules Part 4 — Libraries: import line and setup lines Part 5 — Function reference Part 6 — Complete example projects Part 1 — Instructions for the AI assistant Final reminder for the AI
🤖 Using an AI chatbot? Ask it to read tinkerpy.com/docs/tinkerpy/ (or tinkerpy.com/llms-full.txt) before it writes TinkerPy code, then paste its code into TinkerPy Code and press Compile — Compile checks every line and fixes small mistakes.

Part 2 — The TinkerPy Mega board and its pins

TinkerPy Mega (TinkerKit 2.0) uses an ESP32-C3 chip with WiFi and Bluetooth. It has 4 input pins (i1–i4), 8 output pins (o1–o8), one menu button and an OLED screen connector. Programs are written in TinkerPy Code (tinkerpy.com), compiled, tested in the Simulator and uploaded over WiFi or Bluetooth. Connect each module’s signal pin (S / OUT / DATA / IN) to the board pin, and its VCC and GND to the power and ground pins next to it on the board.

The menu button belongs to the board, not to programs: a program cannot read it (use a push button on an input pin instead). With firmware 2.22+, pressing it while a program runs pauses the program on the Home screen for 3 seconds; pressing it again within those 3 seconds opens the menu (TV Remote, Wireless devices, Debug / Test with OLED Emojis and Buzzer Tones, error codes, RESET board …), otherwise the program carries on by itself. From firmware 2.23, while a program runs that does not use the OLED, the board screen shows ▶ RUNNING and the project name.

2.1 Pin table

PinKindUse it forFixed jobs (when that library is used)
i1input · analogbutton, IR / PIR / touch sensor (ON/OFF) or LDR / soil / knob (analog_read 0–100 or voltage 0.00–3.30 V), DHT11, joystick X, TV remote—
i2input · analogsame as i1; joystick Y—
i3input · analogsame as i1; DHT11 (examples use i3); joystick switchultrasonic Trig (ultrasonic_TX)
i4input · analogsame as i1ultrasonic Echo (ultrasonic_RX)
o1, o2output · PWMLED (with brightness), buzzer, servo, RGB LEDs, driver / relay input—
o3output · PWMsame as o1robot: right motor forward
o4output · PWMsame as o1robot: right motor backward
o5output · PWMsame as o1robot: left motor forward
o6output · PWMsame as o1robot: left motor backward
o7output · PWMsame as o1I2C SDA — OLED / LCD / MPU6050 data
o8output · PWMsame as o1I2C SCL — OLED / LCD / MPU6050 clock
  • OLED, LCD, MPU6050 and the firmware 2.27 I2C sensors (RTC, pulse oximeter, BMP280, VL53L0X, TCS34725, APDS-9960) all share the I2C pins o7/o8 — they can be used together in one project, except two parts with the same address: RTC + MPU6050 (0x68), VL53L0X + TCS34725 (0x29).
  • An output pin can also read a button/sensor: o5 = set_function(active_low) in setup:, then if o5 == ON:.
  • Free pins with a robot + display: outputs o1, o2 and inputs i1, i2 (and i3, i4 when there is no ultrasonic sensor).

2.2 Inputs: ON and OFF

i1 == ON means “the button is pressed / the sensor is triggered”. By default an input is active low (ON when the signal pin is pulled to GND — how most buttons and IR / obstacle modules work). For a module whose output goes HIGH when it detects something (many PIR and touch sensors), add i1 = set_function(active_high) in setup:.

2.3 Where each device goes (AI: use these when you pick pins)

DevicePin(s)Setup line(s)
Push button, IR / PIR / touch / rain / sound sensor (digital)any of i1–i4 (first free)i1 = set_function(active_low) or active_high — an input with no setup line is active_low (Compile adds it)
LDR, soil moisture, potentiometer (analog 0–100)i1–i4i1 = set_function(adc) — read with analog_read(i1) (0–100) or voltage(i1) (0.00–3.30 V). An ADC pin can’t be checked as ON/OFF; compare analog_read(i1) > 50
Ultrasonic HC-SR04Trig i3, Echo i4 (fixed)i3 = set_function(ultrasonic_TX), i4 = set_function(ultrasonic_RX)
DHT11one of i1–i4 (prefer i3, or i1 if the ultrasonic is used)i3 = set_function(dht11)
MPU6050SDA o7, SCL o8 (fixed)o7 = set_function(SDA), o8 = set_function(SCL)
RTC clock (DS3231 / DS1307)SDA o7, SCL o8 (fixed)import rtc + o7 = set_function(SDA), o8 = set_function(SCL)
Pulse oximeter (MAX30100 / MAX30102)SDA o7, SCL o8 (fixed)import pulse_oximeter + o7 = set_function(SDA), o8 = set_function(SCL)
BMP280 pressureSDA o7, SCL o8 (fixed)import bmp280 + o7 = set_function(SDA), o8 = set_function(SCL)
VL53L0X laser distanceSDA o7, SCL o8 (fixed)import vl53l0x + o7 = set_function(SDA), o8 = set_function(SCL)
TCS34725 colourSDA o7, SCL o8 (fixed)import tcs34725 + o7 = set_function(SDA), o8 = set_function(SCL)
APDS-9960 gestureSDA o7, SCL o8 (fixed)import apds9960 + o7 = set_function(SDA), o8 = set_function(SCL)
GPS module (NEO-6M …)any pin (its TX wire)import gps + i1 = set_input(gps_rx)
GSM SIM800L (SMS, calls)any pin for its TX wire, any output for its RX wireimport gsm + i2 = set_input(gsm_rx), o5 = set_output(gsm_tx)
OLED 0.96" (I2C)SDA o7, SCL o8 (fixed)those two + oled_begin()
16x2 LCD (I2C)SDA o7, SCL o8 (fixed)those two + lcd_begin(0x27) (or 0x3F; lcd_begin() finds it)
Joystick (Mega)X and Y on i1–i4, switch on any pini1 = set_function(joystick_x), i2 = set_function(joystick_y), i3 = set_function(joystick_swt)
TV remote receiver TSOP1838any pini1 = set_function(tv_remote) (the 29 keys are learnt on the board: Menu → TV Remote → Learn Remote)
LEDany free outputoptional: o1 = set_function(output)
Buzzerany free outputo1 = set_function(active_buzzer) (beeps) or passive_buzzer (real songs)
Servo SG90 / MG90any free outputo1 = set_function(servo)
Robot car (2 DC motors + driver)o3–o6 (fixed)the four motor_… lines (Part 4)
Small pump / fan / motor, relay moduleany free output (through a driver / relay)optional: o1 = set_function(output)
RGB LEDs WS2812B (1, 2, 3 or a strip)any free outputrgb_begin(o1, number_of_leds)
Bluetooth / IoT (TinkerPy App)no pinBluetooth: bluetooth_begin(); IoT: none (board connects to WiFi by itself)

2.4 Timing

  • wait(ms) pauses the program (1000 ms = 1 second). Counters (c1.auto_increment), the clock, servo scans and RGB effects keep running in the background while the program waits.
  • The program runs loop: again and again very fast. Bluetooth/IoT data is read once per pass.

2.5 Screens and sensors — practical tips

  • OLED: each oled_write fills one whole line, so a label and its number go on separate lines (e.g. line 1 "Temp (C)" small, line 2 the number in large). Plan the 4 lines: medium / large use 2 lines each. For a label and a number on the same line use the 16x2 LCD: lcd_write(1, 1, "Temp:") + lcd_write(1, 7, t).
  • Update a screen with a wait() (200–1000 ms) in the loop so it does not flicker.
  • Analog sensors (LDR, soil, knob) give 0–100. Modules differ (some soil sensors give a HIGH value when dry): tell the student to show the value on the screen in both conditions and then set the threshold.
  • Time events (if HH == 9 and MM == 0:) stay true for a whole minute: use a variable so the action happens once (if HH == 9 and MM == 0 and rang == 0: … rang = 1, and set rang = 0 again when MM != 0).
  • Clock on a screen: numbers show without a leading zero (9:5). Show HH, MM and SS on separate OLED lines, or on the LCD write "0" first when the value is below 10: if MM < 10: lcd_write(1, 4, "0") + lcd_write(1, 5, MM).
  • Which screen? Use the OLED by default (big / bold / centred text). Use the 16x2 LCD when a label and a number must share a line.
  • PIR motion sensors need about 30–60 seconds after power-on before they work reliably.
  • DHT11: read it about every 2 seconds (wait(2000)). Ultrasonic: about 2–400 cm, −1 when nothing is in range.
  • RTC clock: put rtc_set_time(h, m, s) / rtc_set_date(d, m, y) in setup: — the board sets the clock once when the new code arrives (not at every power-on).
  • Pulse oximeter: a fingertip resting gently, no pressing, no moving; heart_rate() / spo2() are 0 until a few beats are measured. heart_beat() is 1 at each beat. Learning only — never for medical decisions.
  • Gesture (APDS-9960): each swipe is seen in one pass of loop:, so compare it in the same pass (if gesture() == "up": … elif gesture() == "down":) or store it first: g = gesture().
  • Colour sensor: hold the colour 1–2 cm away; check color_name() on the screen for your own papers first (lighting changes colours).
  • GPS works outdoors (a minute to find satellites); gps_location() is text for a screen, an SMS or the app. GSM: a SIM800L needs its own 4 V, 2 A supply; send an SMS on a change (a button press, a new alarm), not every loop — the board sends the same SMS only once in 5 minutes.

2.6 Testing in the Simulator

In TinkerPy Code: Compile → Simulator → Start. A tile appears for each pin and device the program uses (more can be added with the edit / catalog button). Press or hold an input tile to press a button; drag sliders for analog pins, the ultrasonic distance, DHT11 temperature / humidity, MPU6050 tilt and turn (plus Shake / Fall / Step buttons) and the joystick. Firmware 2.27 sensors have their own tiles: the RTC clock (your computer’s time), the pulse oximeter (finger on / off, heart-rate and SpO₂ sliders), BMP280 (altitude, temperature), laser distance, the colour sensor (colour picker and swatches) and gesture (swipe buttons and a nearness slider). Firmware 2.28: a GPS tile (fix on / off, walk N / S / E / W, speed) and a GSM phone tile (SMS from the board appear there; send an SMS to the board or call it). The Bluetooth / IoT message box sends a letter, text, number, position or colour to the program, like the TinkerPy App. Output tiles show LEDs (brightness), servo angles, the robot, buzzer, RGB LEDs, OLED and LCD.

2.7 TinkerPy Mini (only if the user says so)

TinkerPy Mini (ESP8266) has only inputs i1, i2 (ultrasonic on i1/i2), outputs o1–o8 like Mega, no Bluetooth and no joystick. Everything else is the same.

Part 3 — Program structure and language rules

3.1 The parts of a program

PartWhat it isExample
CommentsNotes for people. Start with #. The first lines say the project name.# ===== Night Lamp =====
ImportsOne line per library (Part 4). They switch the library on in the editor.import oled_display
Pin namesOptional friendly names for pins, written before setup:. Use the new name everywhere after.o1 = set_name("lamp") then lamp = ON
setup:Runs once at power-on: pin settings, begin() calls, starting values.setup:
    o2 = set_function(servo)
loop:Runs forever, top to bottom, again and again. (Code written after setup: without loop: also repeats — always write loop: for clarity.)loop:
    o1 = ON

3.2 Values

  • Numbers: whole numbers −32768 … 32767, also negative (-5) and hex (0x27); a number outside this range is a compile error, and a maths result outside it wraps round (32767 + 1 gives −32768). Decimals (1.6) only as volts next to voltage() (firmware 2.24; the board keeps millivolts, 1.6 → 1600).
  • ON / OFF: for inputs (pressed / not pressed) and outputs (full on / off). 1 and 0 also work for outputs.
  • None: “nothing arrived” from the app / remote. Compare with != None or == None.
  • Text in double quotes "Hello" — can go in a text variable (2.24), be joined with +, compared, shown and sent (rule 7 of 1.5).
  • Special read-only values: HH, MM, SS (clock), c1 … c8 (counters), pins i1 … i4.

3.3 Variables

Create a variable by giving it a value: count = 0. Change it: count = count + 1. Up to 10 variables. A variable can hold a number, a reading (d = distance()), a counter or clock value, or a character from the app (k = bluetooth_read_char(), then if k == "F":). To remember something between loop passes (a score, a mode, “armed”), give the starting value in setup:.

Text variables (firmware 2.24): a variable that is given text holds text — up to 6 of them, 30 characters each, on top of the 10 number variables. Join with + (numbers become digits). A message from the app or another board is there for one loop, so keep it like this:

setup:
    TP00000002.connect()
    oled_begin()
    last = "-"                          # a text variable
loop:
    if TP00000002.available() == 1:
        last = TP00000002.read()        # keep the newest message
    t = dht_temperature(i3)
    oled_write(1, left, small, regular, "Got: " + last)
    oled_write(2, left, small, regular, "T: " + t + " C")
setup:
    mode = 0              # remembered between passes

loop:
    if i1 == ON:
        mode = mode + 1   # next mode on each press
        if mode > 2:
            mode = 0
        wait(300)         # one press = one step

3.4 Maths, comparisons and logic

KindSymbolsExample
Maths+ - * / % and brackets ( )avg = (a + b) / 2
Compare== != < > <= >=if temp >= 30:
Logicand or notif i1 == ON and not (i2 == ON):
Randomrandom(a, b)dice = random(1, 6)

Write each comparison in full: if x > 1 and x < 5: (not 1 < x < 5).

3.5 Decisions and loops

FormMeaning
if c: / elif c: / else:Do the indented lines only when the condition is true (checked top to bottom).
repeat(n):Do the indented lines n times (n may be a variable). n = 0 or less: not at all.
for i in range(n):Do it n times with i = 0, 1 … n−1 (range(0): not at all). range() takes one value only.
while c:Repeat while the condition is true. Put a wait() inside when it waits for a sensor.
breakLeave the nearest repeat / for / while early.
loop:
    # wait here until the button is pressed
    while i1 == OFF:
        wait(20)
    repeat(3):            # blink 3 times
        o1 = ON
        wait(200)
        o1 = OFF
        wait(200)
    for i in range(10):   # fade up: 0, 10, 20 … 90
        o2 = pwm(i * 10)
        wait(50)

3.6 Common mistakes → correct TinkerPy

WrongRight
o1 = 50o1 = pwm(50)
count += 1count = count + 1
while True:loop: (it already repeats forever)
def blink():no functions — write the lines where needed, or use repeat
print("hi")oled_write(1, left, small, regular, "hi") or bluetooth_write("hi")
time.sleep(1)wait(1000)
for i in range(0, 100, 10):for i in range(10): and use i * 10
name = "Ravi"text cannot go in a variable — write it directly: oled_write(1, left, small, regular, "Ravi")
oled_write(1, 1, "Hi") (old form)oled_write(1, left, small, regular, "Hi")
count = 0 at the top of loop:put count = 0 in setup:
clock_start(…) / c1.set(…) in loop:in setup: (in loop: only inside an if, e.g. a reset button)
o3 = ON with import motorrobot_control("F", 80, "F", 80)
if o1 == ON:outputs cannot be read — keep a variable, e.g. light = 1
temp = 25.5whole numbers only: temp = 25 (decimals are only for volts: if voltage(i1) > 1.6:)

Part 4 — Libraries: import line and setup lines

Every library a program uses needs its import line at the top and its setup lines inside setup:. Core features (inputs, outputs, analog_read, voltage, wait, random, if, loops, variables) need no import.

LibraryImport lineSetup lines (inside setup:)Notes
Servoimport servo
o1 = set_function(servo)
One line per servo, on any free output.
Ultrasonicimport ultrasonic
i3 = set_function(ultrasonic_TX)
i4 = set_function(ultrasonic_RX)
Fixed pins: Trig i3, Echo i4. distance() gives cm.
MPU6050import mpu6050
o7 = set_function(SDA)
o8 = set_function(SCL)
Fixed I2C pins. Keep the board still for the first second after power-on.
RTC clock (DS3231 / DS1307)import rtc
o7 = set_function(SDA)
o8 = set_function(SCL)
Real time and date, kept by the module’s battery. rtc_set_time / rtc_set_date in setup: set it once per new code. Address 0x68 — not together with the MPU6050. Firmware 2.27.
Pulse oximeter (MAX30100 / MAX30102)import pulse_oximeter
o7 = set_function(SDA)
o8 = set_function(SCL)
Heart rate and SpO₂ from a fingertip. For learning only. Address 0x57. Firmware 2.27.
BMP280 pressureimport bmp280
o7 = set_function(SDA)
o8 = set_function(SCL)
Air pressure (hPa), temperature, altitude (m). Address 0x76 / 0x77. Firmware 2.27.
VL53L0X laser distanceimport vl53l0x
o7 = set_function(SDA)
o8 = set_function(SCL)
3 cm – 2 m in cm, 999 = nothing. Address 0x29 — not together with the TCS34725. Firmware 2.27.
TCS34725 colourimport tcs34725
o7 = set_function(SDA)
o8 = set_function(SCL)
Colour name and R G B. Address 0x29 — not together with the VL53L0X. Firmware 2.27.
APDS-9960 gestureimport apds9960
o7 = set_function(SDA)
o8 = set_function(SCL)
Swipes up / down / left / right, nearness, and colour. Address 0x39. Firmware 2.27.
GPS (NEO-6M …)import gps
i1 = set_input(gps_rx)
Any pin: the GPS module's TX wire → this pin. Firmware 2.28.
GSM SIM800Limport gsm
i2 = set_input(gsm_rx)
o5 = set_output(gsm_tx)
Any pins: module TX → gsm_rx, module RX → gsm_tx (an output). Own 4 V 2 A supply. Firmware 2.28.
OLED Displayimport oled_display
o7 = set_function(SDA)
o8 = set_function(SCL)
oled_begin()
Fixed I2C pins. 4 text lines.
16x2 LCD Displayimport lcd_16x2
o7 = set_function(SDA)
o8 = set_function(SCL)
lcd_begin(0x27)
Fixed I2C pins. 2 lines × 16 letters.
DHT11import dht11
i3 = set_function(dht11)
Any input i1–i4; all DHT11 readings use the same pin.
Counterimport counter
c1.set(0)            # optional starting value
Eight counters c1–c8. No pins.
Clockimport clock
clock_start(7, 0, 0)  # hour, minute, second
A software clock. Set it to the real time.
Bluetoothimport bluetooth
bluetooth_begin()
TinkerPy Mega only. Talks to the TinkerPy App over Bluetooth.
IoTimport iot
(no setup line)
Talks to the TinkerPy App over the internet (board needs WiFi).
Robot (motors)import motor
o3 = set_function(motor_right_forward)
o4 = set_function(motor_right_backward)
o5 = set_function(motor_left_forward)
o6 = set_function(motor_left_backward)
Fixed pins o3–o6 through a motor driver.
RGB LED (1 LED board)import rgb_single
rgb_begin(o1, 1)
A board with 1 RGB LED on any free output.
RGB LED (2 LED board)import rgb_two
rgb_begin(o1, 2)
A board with 2 RGB LEDs.
RGB LED (3 LED board)import rgb_three
rgb_begin(o1, 3)
A board with 3 RGB LEDs.
RGB LED stripimport rgb_strip
rgb_begin(o1, 30)
A strip: the number is how many LEDs it has (1–60).
Joystick (Mega)import joystick
i1 = set_function(joystick_x)
i2 = set_function(joystick_y)
i3 = set_function(joystick_swt)
TinkerPy Mega. X/Y need i1–i4; the switch can be any pin; leave out what is not wired.
TV Remote (IR)import tv_remote
i1 = set_function(tv_remote)
Any pin. Learn the remote’s keys on the board: Menu → TV Remote.
Wireless (board to board)import wireless
TP00000002.connect()
No wires: the other board’s Device ID (Menu → Device info). Up to 6 boards; both boards’ programs must list each other. TinkerPy Mega, firmware 2.24.
Wireless IoT (over the internet)import wireless_iot
TP00000002_iot.connect()
Boards anywhere, each on WiFi; tinkerpy.com passes the messages (a few seconds). Both programs must list each other. TinkerPy Mega, firmware 2.25.
Buzzerimport buzzer
o1 = set_function(active_buzzer)
Any free output. Use passive_buzzer for real songs.

Part 5 — Function reference

Every function, keyword and value of TinkerPy, grouped like the editor’s palette. Each entry gives the exact form, what it does, what each value means and working examples. Examples show the important lines; a full program also needs the import and setup lines from Part 4 (TinkerPy Code adds missing ones when you press Compile). “Firmware” is the oldest board firmware that runs it.

5.1 Quick list of all functions

GroupForms
Pins, setup and outputs (core)pin = set_input(device, mode) · pin = set_output(device[, value]) · pin = set_function(type) · pin = set_name("name") · input == ON / input == OFF · output = ON / OFF / 1 / 0 · output = pwm(value) · output = servo_angle(angle)
Control flowDigital input condition if i1 == ON: · Analog input condition if analog_read(i1) < 30: / if voltage(i1) > 1.6: · if <condition>: · elif <condition>: · else:
Looprepeat(count): · for <name> in range(count): · while condition: · break
Arithmetic and Logicrandom(smallest, biggest) · a + b, a - b, a * b, a / b, a % b · a == b, a != b, a < b, a > b, a <= b, a >= b · a and b, a or b, not a
General Codewait(milliseconds) · wifi("network", "password")
Analog Inputanalog_read(input) · voltage(input)
Servo Functionservo_write_angle(output, angle) · servo_increment(output, step, max_angle, step_delay) · servo_decrement(output, step, min_angle, step_delay) · servo_increment_till(output, start_angle, end_angle, step, step_delay) · servo_decrement_till(output, start_angle, end_angle, step, step_delay) · servo_oscillate(output, home_angle, angle_a, angle_b, step, step_delay) · servo_flip(output, start_angle, end_angle, step, step_delay) · servo_scan_on(output, start_angle, end_angle, step, step_delay) · servo_scan_stop(output) · servo_scan_resume(output) · servo_read_angle(output) · servo_sync(output_a, output_b) · servo_sync_reverse(output_a, output_b)
Output Function<output> = <value> · <output> = invert(<pin>) · output_increment(output, step, max_value, step_delay) · output_decrement(output, step, min_value, step_delay) · output_increment_till(output, start_value, end_value, step, step_delay) · output_decrement_till(output, start_value, end_value, step, step_delay) · output_flip(output, off_value, on_value)
Ultrasonic Functiondistance()
DHT11 Functiondht_temperature(input) · dht_humidity(input)
MPU6050 Functiontilt_x() · tilt_y() · tilt_direction() · shake_detected() · motion_level() · fall_detected() · turn_angle() · reset_turn() · step_count() · reset_steps() · accel_x() · accel_y() · accel_z() · gyro_x() · gyro_y() · gyro_z() · mpu_temperature()
RTC Clock Functionrtc_hour() · rtc_minute() · rtc_second() · rtc_day() · rtc_month() · rtc_year() · rtc_weekday() · rtc_set_time(hour, minute, second) · rtc_set_date(day, month, year)
Pulse Oximeter Functionheart_rate() · spo2() · finger_detected() · heart_beat()
BMP280 Functionpressure() · bmp_temperature() · altitude()
Laser Distance Functionlaser_distance()
Colour Sensor Functioncolor_name() · color_red() · color_green() · color_blue() · color_brightness()
Gesture Functiongesture() · proximity()
GPS Functiongps_found() · gps_satellites() · gps_speed() · gps_altitude() · gps_hour() · gps_minute() · gps_second() · gps_save_home() · gps_distance_home() · gps_location()
GSM Functiongsm_send_sms("number", message) · gsm_sms_received() · gsm_read_sms() · gsm_sms_number() · gsm_call("number") · gsm_hang_up() · gsm_ringing() · gsm_signal()
Buzzer Functionbuzzer_play(output, "tone") · buzzer_play_background(output, "tone", repeat) · buzzer_stop_background(output) · is_buzzer_playing(output)
TV Remote Functionremote_read()
Joystick Functionjoystick_x() · joystick_y() · joystick_direction() · joystick_pressed()
RGB LED Functionrgb_begin(output, number_of_leds) · rgb_color(output, led, "color", brightness) · rgb_flip(output, led, "color", brightness) · rgb_hex_color(output, led, r, g, b) · rgb_blink(output, led, "color", on_ms, off_ms) · rgb_breathe(output, led, "color", time_ms) · rgb_swap(output, led, "color", "color2", time_ms) · rgb_chase(output, led, "color", speed_ms) · rgb_wipe(output, led, "color", speed_ms) · rgb_twinkle(output, led, "color", speed_ms) · rgb_bar(output, led, "color", value, max) · rgb_heat(output, led, "color", value, low, high)
LCD Display Functionlcd_begin(address) · lcd_write(line, position, value) · lcd_clear() · lcd_clear_line(line) · lcd_scroll(line, text) · lcd_backlight(ON / OFF)
OLED Display Functionoled_begin(address) · oled_write(line, align, size, weight, value) · oled_clear() · oled_clear_line(line) · oled_eye_animation(name, repeat, speed, delay) · oled_emoji_animation(name, repeat, speed, delay) · oled_scroll(line, text)
Counter Functionc1.auto_increment(interval_ms) · c1.auto_decrement(interval_ms) · c1.increment() · c1.decrement() · c1.clear() · c1.pause() · c1.set(value)
Clock Functionclock_start(hours, minutes, seconds) · HH, MM, SS · clock_speed(real_ms_per_second) · clock_pause() · clock_resume()
Bluetooth & IoT Functionbluetooth_begin() · bluetooth_connected() · bluetooth_write(value) · bluetooth_write(a, b[, c]) · bluetooth_read_char() · bluetooth_read_string() · bluetooth_read_number() · x, y = bluetooth_read_position() · r, g, b = bluetooth_read_rgb() · set_device_password("1234") · iot_write(value) · iot_write(a, b[, c]) · iot_read_char() · iot_read_string() · iot_read_number() · x, y = iot_read_position() · r, g, b = iot_read_rgb()
Robot Functionrobot_control(left_dir, left_speed, right_dir, right_speed) · motor_control_right(direction, speed) · motor_control_left(direction, speed) · robot_forward(speed) · robot_backward(speed) · robot_left(speed) · robot_right(speed) · robot_arc_left(speed) · robot_arc_right(speed) · robot_stop()

5.2 Details and examples

Pins, setup and outputs (core)

pin = set_input(device, mode)

Inside setup: — says what is connected to an input pin (the newer, clearer form of set_function). ON / OFF modules MUST give their mode: active_low (ON when the pin reads LOW — most modules) or active_high (ON when HIGH — PIR and touch, marked *). 0–100 modules use adc (i1–i4 only). dht11, tv_remote, ultrasonic_trig (i3), ultrasonic_echo (i4), gps_rx and gsm_rx (any pin, firmware 2.28) have no mode; gsm_tx is set with set_output(gsm_tx). The device name is for the editor and the simulator (it shows that module); the board runs it exactly like set_function, so no new firmware is needed. ON/OFF modules: push_button, general (switch), slide_switch, limit_switch, touch*, pir*, ir_sensor, sound, flame, vibration, reed, hall, tilt, rain, water, line_sensor, light_sensor, soil, lpg, alcohol, air_quality, joystick_swt. 0–100 modules: potentiometer, water_level, temperature, flex, joystick_x, joystick_y — and light_sensor, soil, lpg, alcohol, air_quality, general (these have both outputs: ON/OFF or adc).

pini1–i4 (or o1–o8 for an ON/OFF module used as an input), or its set_name name.
deviceWhat is connected — one of the names above (no quotes).
modeactive_low · active_high · adc.
Example 1 — A motion sensor (PIR) on i1 turns a light on.
setup:
    i1 = set_input(pir, active_high)
loop:
    if i1 == ON:
        o1 = ON
    else:
        o1 = OFF
Example 2 — A light sensor read as 0–100 — a night lamp.
setup:
    i2 = set_input(light_sensor, adc)
loop:
    if analog_read(i2) < 30:
        o1 = ON
    else:
        o1 = OFF
Example 3 — A gas sensor (MQ-2) alarm on its ON/OFF output.
setup:
    i3 = set_input(lpg, active_low)
    o2 = set_output(buzzer)
loop:
    if i3 == ON:
        o2 = ON
    else:
        o2 = OFF
pin = set_output(device[, value])

Inside setup: — says what is connected to an output pin (o1–o8). Outputs have no mode. Devices: led, bulb, laser, relay, motor, fan, pump, lock, vibration, buzzer (buzzer, passive = tunes), servo (servo, 90 = start angle), rgb_led (rgb_led, 8 = how many LEDs), right_motor_P / right_motor_N (o3/o4), left_motor_P / left_motor_N (o5/o6). With only ONE robot motor set up, its partner’s two pins are free for other things; P and N may be swapped on a motor’s own two pins when it turns the wrong way (robot_control and motor_control_right/left then drive it the right way). robot_control(...) needs both motors.

pino1–o8.
deviceWhat is connected (no quotes).
valueservo: start angle 0–180 · rgb_led: number of LEDs 1–60 · buzzer: passive for tunes. Nothing for the others.
Example 1 — A fan at 60 % and a servo that starts at 90°.
setup:
    o1 = set_output(fan)
    o2 = set_output(servo, 90)
loop:
    o1 = pwm(60)
    o2 = servo_angle(45)
Example 2 — An 8-LED RGB strip on o3.
setup:
    o3 = set_output(rgb_led, 8)
loop:
    rgb_color(o3, all, "rainbow", 80)
Example 3 — One motor only, P and N swapped (it turned the wrong way) — o5 and o6 stay free.
setup:
    o3 = set_output(right_motor_N)
    o4 = set_output(right_motor_P)
    o5 = set_output(led)
loop:
    motor_control_right('F', 70)
    o5 = ON
pin = set_function(type)

Inside setup: — the older form of set_input / set_output (still works). Types (no quotes): servo, dht11, output, active_low, active_high, active_buzzer, passive_buzzer, tv_remote, joystick_x, joystick_y, joystick_swt, ultrasonic_TX (i3), ultrasonic_RX (i4), SDA (o7), SCL (o8), motor_right_forward (o3), motor_right_backward (o4), motor_left_forward (o5), motor_left_backward (o6).

pini1–i4 or o1–o8 (or its set_name name).
typeOne of the types above.
Example 1 — A servo on o2 and a DHT11 on i3.
setup:
    o2 = set_function(servo)
    i3 = set_function(dht11)
Example 2 — A sensor whose output goes HIGH when it detects (many PIR / touch modules).
setup:
    i1 = set_function(active_high)
loop:
    if i1 == ON:
        o1 = ON
    else:
        o1 = OFF
Example 3 — Use output pin o5 as an extra button input.
setup:
    o5 = set_function(active_low)
loop:
    if o5 == ON:
        o1 = ON
    else:
        o1 = OFF
pin = set_name("name")

Gives a pin an easy name. Write it before setup:, then use the name everywhere instead of the pin. TinkerPy Code names each part added in the Circuit Connections window the same way — light_sensor_1, motion_sensor_1, servo_motor_1, led_2 … (rename it there if you like).

nameLetters, digits and _ , in quotes, starting with a letter.
Example 1 — Names make code easy to read.
i1 = set_name("door")
o1 = set_name("alarm")

loop:
    if door == ON:
        alarm = ON
    else:
        alarm = OFF
input == ON / input == OFF

Reads a digital input: ON when the button is pressed or the sensor is triggered. Use it in if / elif / while.

inputi1–i4, an o-pin set as active_low / active_high, or its set_name name.
Example 1 — A doorbell light.
if i1 == ON:
    o1 = ON
else:
    o1 = OFF
output = ON / OFF / 1 / 0

Switches an output fully on or off (LED, buzzer, relay, driver).

outputo1–o8 or its set_name name.
Example 1 — Blink o1 every half second.
o1 = ON
wait(500)
o1 = OFF
wait(500)
output = pwm(value)

Sets an output’s power from 0 to 100 % — LED brightness, motor / fan speed. A variable or a sum can also be given directly: output = level.

value0–100 (a number, variable or sum). Out-of-range values are clamped.
Example 1 — Half brightness.
o1 = pwm(50)
Example 2 — A knob on i1 sets the brightness.
o1 = pwm(analog_read(i1))
output = servo_angle(angle)

Moves a servo to an angle at once (same as servo_write_angle).

angle0–180 degrees (a number, variable or sum).
Example 1 — Open a gate while the button is pressed.
setup:
    o1 = set_function(servo)
loop:
    if i1 == ON:
        o1 = servo_angle(90)
    else:
        o1 = servo_angle(0)

Control flow

if <condition>:

Runs the indented lines below only when the condition is true.

conditionA comparison, like i1 == ON or count > 5.
Example 1 — Turns o1 on while i1 is pressed, off otherwise.
if i1 == ON:
    o1 = pwm(100)
else:
    o1 = 0
Example 2 — Turns o1 on only when BOTH buttons are pressed.
if i1 == ON and i2 == ON:
    o1 = pwm(100)
Example 3 — Checks a variable’s value, not just a pin.
count = 0
if count == 0:
    o1 = pwm(100)
elif <condition>:

Checked only if the earlier if (and any earlier elif) was false.

conditionA comparison, checked in order after the if.
Example 1 — Different pins give different output levels.
if i1 == ON:
    o1 = pwm(100)
elif i2 == ON:
    o1 = pwm(50)
else:
    o1 = 0
Example 2 — Checks a variable against different thresholds.
count = 5
if count > 10:
    o1 = pwm(100)
elif count > 5:
    o1 = pwm(50)
else:
    o1 = 0
Example 3 — elif can check the SAME pin again with a different condition.
if i1 == ON:
    o1 = pwm(100)
elif i1 == OFF:
    o1 = 0
else:

Runs when none of the if/elif conditions above were true.

Example 1 — Runs when the if condition was false.
if i1 == ON:
    o1 = pwm(100)
else:
    o1 = 0
Example 2 — else can run multiple lines too.
if i1 == ON:
    o1 = pwm(100)
else:
    o1 = 0
    o2 = pwm(100)
Example 3 — else is the fallback when no earlier condition matched.
if i1 == ON:
    o1 = pwm(100)
elif i2 == ON:
    o1 = pwm(50)
else:
    o1 = 0

Loop

repeat(count):

Runs the indented lines below a fixed number of times.

countHow many times to repeat (a number, up to 1000).
Example 1 — Blinks o1 three times.
repeat(3):
    o1 = pwm(100)
    wait(200)
    o1 = 0
    wait(200)
Example 2 — Counts up to 10 using a variable.
count = 0
repeat(10):
    count = count + 1
o1 = count
Example 3 — Loops can be nested inside each other.
repeat(5):
    repeat(2):
        o1 = pwm(100)
        wait(100)
for <name> in range(count):

Like repeat, but also gives you a counter you can use inside the loop.

nameWhat to call the counter (e.g. i).
countHow many times to loop (up to 1000).
Example 1 — Ramps o1 through 0, 20, 40, 60, 80.
for i in range(5):
    o1 = i * 20
Example 2 — Adds up 0 through 9 using the loop counter.
count = 0
for i in range(10):
    count = count + i
o1 = count
Example 3 — Works like repeat, but you also get a counter (i) if you need it.
for i in range(3):
    o1 = pwm(100)
    wait(300)
    o1 = 0
    wait(300)
while condition:
Firmware: 2.15+

Repeats the indented lines again and again, as long as the condition is true. Needs firmware 2.15+.

conditionChecked before every round, e.g. i1 == ON or count < 10.
Example 1 — Keeps the light on while the button is held, then turns it off.
while i1 == ON:
    o1 = ON
    wait(100)
o1 = OFF
Example 2 — Counts 1 to 5 on the display, then moves on.
count = 0
while count < 5:
    count = count + 1
    oled_write(1, left, small, regular, count)
    wait(500)
Example 3 — Drives forward until something is closer than 20 cm, then stops.
while distance() > 20:
    robot_control("F", 60, "F", 60)
robot_control("S", 0, "S", 0)
break
Firmware: 2.15+

Leaves the loop it is in (while, repeat or for) straight away. Needs firmware 2.15+.

Example 1 — Blinks up to 100 times, but a button press stops it early.
repeat(100):
    o1 = ON
    wait(100)
    o1 = OFF
    wait(100)
    if i1 == ON:
        break
Example 2 — Stops counting at 7 and shows it.
n = 0
while n < 1000:
    n = n + 1
    if n == 7:
        break
oled_write(1, left, small, regular, n)
Example 3 — Brightens step by step until the app sends S.
for i in range(10):
    if bluetooth_read_char() == 'S':
        break
    o1 = i * 10
    wait(300)

Arithmetic and Logic

random(smallest, biggest)
Firmware: 2.15+

Gives a surprise whole number between the two numbers (both included). Needs firmware 2.15+.

smallestThe smallest number it can give, e.g. 1.
biggestThe biggest number it can give, e.g. 6.
Example 1 — An electronic dice: press the button to roll 1 to 6.
if i1 == ON:
    dice = random(1, 6)
    oled_write(1, left, small, regular, dice)
    wait(500)
Example 2 — A flickering candle: a new random brightness every 0.2 s.
o1 = pwm(random(10, 100))
wait(200)
Example 3 — A reaction game: the light comes on after a surprise wait of 1 to 5 seconds.
wait(random(1000, 5000))
o1 = ON
a + b, a - b, a * b, a / b, a % b

The five math operators — combine numbers and variables just like a calculator.

Example 1 — Addition: a becomes 8.
a = 5 + 3
o1 = a
Example 2 — Subtraction: a becomes 7.
a = 10 - 3
o1 = a
Example 3 — Multiplication: a becomes 8.
a = 4 * 2
o1 = a
Example 4 — Division: a becomes 4 — TinkerPy drops any remainder, so it’s always a whole number.
a = 9 / 2
o1 = a
Example 5 — Remainder (modulo): a becomes 1 — what’s left over after dividing 9 by 2.
a = 9 % 2
o1 = a
a == b, a != b, a < b, a > b, a <= b, a >= b

Compares two values and gives a true/false answer — used inside if/elif to decide what runs.

Example 1 — Equal to — true when i1 is pressed.
if i1 == ON:
    o1 = pwm(100)
Example 2 — Not equal to — true whenever i1 is NOT pressed.
if i1 != ON:
    o1 = OFF
Example 3 — Less than.
count = 3
if count < 5:
    o1 = pwm(100)
Example 4 — Greater than.
count = 8
if count > 5:
    o1 = pwm(100)
Example 5 — Greater than OR equal to — true at exactly 5, and above.
count = 5
if count >= 5:
    o1 = pwm(100)
a and b, a or b, not a

Combines two conditions into one, or flips a condition around — for when a single comparison isn’t enough.

Example 1 — and: true only when BOTH conditions are true.
if i1 == ON and i2 == ON:
    o1 = pwm(100)
Example 2 — or: true when AT LEAST ONE condition is true.
if i1 == ON or i2 == ON:
    o1 = pwm(100)
Example 3 — not: flips true to false and false to true.
if not i1 == ON:
    o1 = pwm(100)
Example 4 — Combining and + not: on only when i1 is pressed but i2 is NOT.
if i1 == ON and not i2 == ON:
    o1 = pwm(100)

General Code

wait(milliseconds)

Pauses the program for a moment before continuing.

milliseconds1000 = one second. A number from 0 to 65535 (about 65 seconds); for longer, put the wait inside a repeat.
Example 1 — Turns o1 on for half a second, then off.
o1 = pwm(100)
wait(500)
o1 = 0
Example 2 — A short wait makes a fast blink.
repeat(5):
    o1 = pwm(100)
    wait(100)
    o1 = 0
    wait(100)
Example 3 — Waits 2 seconds before doing anything.
wait(2000)
o1 = pwm(100)
wifi("network", "password")

Lets your TinkerKit connect to a second WiFi network besides the default one.

networkThe WiFi network name (SSID), in quotes.
passwordThe WiFi password, in quotes.
Example 1 — Connects to your home WiFi, then runs the rest of the code as normal.
setup:
    wifi("HomeNetwork", "mypassword123")
loop:
    o1 = pwm(100)
Example 2 — A second network for using the TinkerKit somewhere other than school.
setup:
    wifi("Classroom-2A", "school2024")
Example 3 — Works with a phone hotspot too.
setup:
    wifi("MyPhoneHotspot", "hotspot99")
loop:
    if i1 == ON:
        o1 = pwm(100)

Analog Input

Two ways to read an analog sensor (LDR, knob, soil sensor) on i1–i4: analog_read gives 0 – 100, voltage gives volts 0.00 – 3.30. Compile swaps one for the other when the numbers say so: if analog_read(i1) < 1.3: becomes if voltage(i1) < 1.3:, if voltage(i1) < 40: becomes if analog_read(i1) < 40:.

analog_read(input)
Firmware: 2.15+

Reads how much voltage is on an input pin, as 0 to 100 — for a light sensor, a knob or a soil sensor. Set the pin as adc in setup:.

inputi1, i2, i3 or i4. That pin is then not used as an ON/OFF button.
Example 1 — A night lamp: an LDR on i1 turns the light on when it gets dark.
light = analog_read(i1)
if light < 30:
    o1 = ON
else:
    o1 = OFF
Example 2 — A dimmer: turn the knob (potentiometer) on i2 to set the LED brightness.
o1 = pwm(analog_read(i2))
Example 3 — Shows the soil moisture and runs the pump on o2 when it is dry.
soil = analog_read(i1)
oled_write(1, left, small, regular, soil)
if soil < 40:
    o2 = ON
voltage(input)
Firmware: 2.24+

The volts on an input pin, 0.00 to 3.30. Compare it with decimals like 1.6 (the only place decimals are allowed); it shows as 1.62 on the OLED / LCD, in Bluetooth / IoT / wireless messages and in joined text. pwm(voltage(i1)) treats 3.3 V as 100 %. Set the pin with i1 = set_function(adc) in setup:.

inputi1, i2, i3 or i4. That pin is then not used as an ON/OFF button.
Example 1 — o1 comes on above 1.6 volts.
setup:
    i1 = set_function(adc)
loop:
    v = voltage(i1)
    if v > 1.6:
        o1 = ON
    else:
        o1 = OFF
Example 2 — Shows "Volts: 1.62" on the OLED.
v = voltage(i1)
oled_write(1, left, small, regular, "Volts: " + v)
Example 3 — A dimmer in volts: 3.3 V is full brightness.
o1 = pwm(voltage(i2))

Servo Function

servo_write_angle(output, angle)
Needs: import servo

Sets an output to a servo angle from 0–180°.

outputAn output pin, e.g. o1.
angle0–180. Out-of-range values are clamped automatically.
Example 1 — Points the servo to the middle.
servo_write_angle(o1, 90)
Example 2 — Moves from one end to the other.
servo_write_angle(o1, 0)
wait(500)
servo_write_angle(o1, 180)
Example 3 — A button controls the servo position.
if i1 == ON:
    servo_write_angle(o1, 180)
else:
    servo_write_angle(o1, 0)
servo_increment(output, step, max_angle, step_delay)
Needs: import servo

Increases an output value once, by a fixed step — never past max_angle.

outputAn output pin, e.g. o1.
stepHow much to increase by.
max_angleWon’t go above this, even if the step would push it further.
step_delayHow long the move takes, in milliseconds.
Example 1 — Raises o1 by 10, taking 200ms, capped at 180.
servo_increment(o1, 10, 180, 200)
Example 2 — Ramps up in steps of 20, but stops climbing once it hits 100 — even if called again.
repeat(5):
    servo_increment(o1, 20, 100, 100)
Example 3 — Nudges the value up a little every press, capped at 90.
if i1 == ON:
    servo_increment(o1, 5, 90, 50)
servo_decrement(output, step, min_angle, step_delay)
Needs: import servo

Decreases an output value once, by a fixed step — never below min_angle.

outputAn output pin, e.g. o1.
stepHow much to decrease by.
min_angleWon’t go below this, even if the step would push it further.
step_delayHow long the move takes, in milliseconds.
Example 1 — Lowers o1 by 10, taking 200ms, capped at 0.
servo_decrement(o1, 10, 0, 200)
Example 2 — Ramps down in steps of 20, but stops descending once it hits 20.
repeat(5):
    servo_decrement(o1, 20, 20, 100)
Example 3 — A second button nudges the value back down, capped at 10.
if i2 == ON:
    servo_decrement(o1, 5, 10, 50)
servo_increment_till(output, start_angle, end_angle, step, step_delay)
Needs: import servo

Jumps to start_angle, then climbs step by step up to end_angle.

outputAn output pin, e.g. o1.
start_angleWhere it begins — set immediately, before the climb starts.
end_angleWhere it stops. If this isn’t above start_angle, nothing happens.
stepHow much to increase by each move.
step_delayMilliseconds to pause between steps.
Example 1 — Starts at 0, climbs to 100, 5 at a time.
servo_increment_till(o1, 0, 100, 5, 50)
Example 2 — Sweeps a servo smoothly from 0° up to 180°.
servo_increment_till(o1, 0, 180, 10, 30)
Example 3 — Only climbs while the button is held, always starting from 20.
if i1 == ON:
    servo_increment_till(o1, 20, 100, 10, 20)
servo_decrement_till(output, start_angle, end_angle, step, step_delay)
Needs: import servo

Jumps to start_angle, then descends step by step down to end_angle.

outputAn output pin, e.g. o1.
start_angleWhere it begins — set immediately, before the descent starts.
end_angleWhere it stops. If this isn’t below start_angle, nothing happens.
stepHow much to decrease by each move.
step_delayMilliseconds to pause between steps.
Example 1 — Starts at 100, descends to 0, 5 at a time.
servo_decrement_till(o1, 100, 0, 5, 50)
Example 2 — Sweeps a servo smoothly from 180° back down to 0°.
servo_decrement_till(o1, 180, 0, 10, 30)
Example 3 — Only descends while a second button is held, always starting from 100.
if i2 == ON:
    servo_decrement_till(o1, 100, 20, 10, 20)
servo_oscillate(output, home_angle, angle_a, angle_b, step, step_delay)
Needs: import servo

Sweeps an output back and forth between two points, once, then returns to where it started.

outputAn output pin, e.g. o1.
home_angleWhere the sweep BOTH begins and ends — the servo returns here when finished.
angle_aIt first sweeps to this angle…
angle_b…then to this one, and then back home.
stepHow much the value changes each move.
step_delayMilliseconds to pause between steps.
Example 1 — Sweeps a servo from 0° to 180° and back, like a radar scanner — starts and ends at 0°.
servo_oscillate(o1, 0, 0, 180, 5, 20)
Example 2 — A smaller, repeated sweep between 60° and 120°, but each time it returns to rest at 90° before sweeping again.
repeat(3):
    servo_oscillate(o1, 90, 60, 120, 5, 20)
Example 3 — Only sweeps while the button is pressed, then rests back at 0°.
if i1 == ON:
    servo_oscillate(o1, 0, 0, 180, 10, 10)
servo_flip(output, start_angle, end_angle, step, step_delay)
Needs: import servo · Firmware: 2.14+

Each new press moves the servo the other way: start → end, then end → start. While the condition stays true it stays where it is. Needs firmware 2.14+.

outputAn output pin with a servo, e.g. o1.
start_angleWhere it rests at power-on, and where it returns on every second press.
end_angleWhere the first press moves it to.
stepDegrees per move — bigger is faster.
step_delayMilliseconds to pause between steps.
Example 1 — A gate: press once to open (0° → 90°), press again to close. Holding the button does not move it again.
if i1 == ON:
    servo_flip(o1, 0, 90, 5, 20)
Example 2 — A hand waved near the sensor opens the lid; the next wave closes it.
if distance() < 10:
    servo_flip(o2, 0, 180, 10, 15)
Example 3 — Each D from the app opens or closes the door.
if bluetooth_read_char() == 'D':
    servo_flip(o1, 20, 160, 10, 10)
servo_scan_on(output, start_angle, end_angle, step, step_delay)
Needs: import servo

Starts a servo sweeping back and forth forever, on its own — once started it keeps sweeping in the background, even while the rest of the code is busy or inside a wait().

outputAn output pin, e.g. o1.
start_angleOne end of the sweep.
end_angleThe other end of the sweep.
stepHow much the angle changes each move.
step_delayMilliseconds to pause between steps — controls the sweep speed.
Example 1 — Sweeps continuously between 0° and 180° like a radar dish — bounces back and forth forever, on its own.
setup:
    servo_scan_on(o1, 0, 180, 5, 20)
Example 2 — The scan keeps sweeping the WHOLE 3 seconds this wait(3000) is running — it never pauses for the rest of the code, and the rest of the code never waits for it either.
setup:
    servo_scan_on(o1, 0, 180, 5, 20)
loop:
    wait(3000)
    o2 = pwm(100)
Example 3 — Starts the sweep the moment the button is pressed — once started, it keeps going even after the button is released (use servo_scan_stop(...) to actually stop it).
if i1 == ON:
    servo_scan_on(o1, 0, 180, 5, 20)
Example 4 — Two servos can scan independently at once, each at its own angle range and speed.
setup:
    servo_scan_on(o1, 0, 180, 5, 20)
    servo_scan_on(o2, 30, 150, 10, 15)
servo_scan_stop(output)
Needs: import servo

Freezes a servo_scan_on(...) sweep exactly where it currently is — the servo stops moving, but remembers its position and direction.

outputThe output pin whose scan should freeze, e.g. o1 — must already be scanning via servo_scan_on(...).
Example 1 — Freezes the scan on o1 the instant the button is pressed, wherever it happened to be mid-sweep.
if i1 == ON:
    servo_scan_stop(o1)
Example 2 — Lets the servo scan for 2 seconds, then freezes it in place — it stays exactly where it stopped, not jumping back to 0.
setup:
    servo_scan_on(o1, 0, 180, 5, 20)
loop:
    wait(2000)
    servo_scan_stop(o1)
Example 3 — Freezes the sweep as soon as something gets close, e.g. to avoid hitting an obstacle mid-scan.
if distance() < 10:
    servo_scan_stop(o1)
servo_scan_resume(output)
Needs: import servo

Continues a servo_scan_on(...) sweep that was frozen with servo_scan_stop(...) — picks up from the exact angle and direction it stopped at, not from the beginning.

outputThe output pin whose scan should continue, e.g. o1 — a no-op if that pin was never scanning in the first place.
Example 1 — Holding the button freezes the sweep; releasing it lets the sweep continue right from where it paused.
if i1 == ON:
    servo_scan_stop(o1)
else:
    servo_scan_resume(o1)
Example 2 — Scans for 2 seconds, pauses for 2 seconds, then picks the same sweep back up — never restarting from 0.
setup:
    servo_scan_on(o1, 0, 180, 5, 20)
loop:
    wait(2000)
    servo_scan_stop(o1)
    wait(2000)
    servo_scan_resume(o1)
Example 3 — A second button specifically resumes o2’s own scan, independent of whatever o1 is doing.
if i2 == ON:
    servo_scan_resume(o2)
servo_read_angle(output)
Needs: import servo

Reads a servo’s CURRENT angle (0–180) — whatever it actually is right now, however it got there: a plain angle set with servo_angle(...), still mid-way through an increment/decrement/oscillate, or a servo_scan_on(...) sweep that’s either actively running or frozen with servo_scan_stop(...).

outputThe output pin the servo is on, e.g. o1.
Example 1 — Stores the servo’s current angle in a variable.
a = servo_read_angle(o1)
Example 2 — Turns on a light only while the servo is past the halfway point.
if servo_read_angle(o1) > 90:
    o2 = ON
else:
    o2 = OFF
Example 3 — Scans for 2 seconds, freezes the sweep, then reads exactly where it stopped.
setup:
    servo_scan_on(o1, 0, 180, 5, 20)
loop:
    wait(2000)
    servo_scan_stop(o1)
    a = servo_read_angle(o1)
servo_sync(output_a, output_b)
Needs: import servo

Links two servos so they always move together — from this point on, ANY way either one’s angle changes (servo_angle(...), increment/decrement/oscillate, or a servo_scan_on(...) sweep) is mirrored onto the other automatically. Immediately matches the second pin to the first’s current angle when called.

output_aThe first servo’s output pin, e.g. o1.
output_bThe second servo’s output pin, e.g. o2 — must be different from output_a.
Example 1 — Both o1 and o2 move to 90° — setting either one from here on moves both.
setup:
    servo_sync(o1, o2)
loop:
    o1 = servo_angle(90)
Example 2 — o2 sweeps in perfect lockstep with o1’s scan, with no scan of its own needed.
setup:
    servo_sync(o1, o2)
    servo_scan_on(o1, 0, 180, 5, 20)
Example 3 — Links the two servos together only once the button has been pressed.
if i1 == ON:
    servo_sync(o1, o2)
servo_sync_reverse(output_a, output_b)
Needs: import servo

Links two servos to always move OPPOSITE each other — the second pin’s angle is kept at exactly 180 minus the first’s, through any of the same mechanisms servo_sync(...) covers (a direct set, increment/decrement/oscillate, or a scan). Useful for a pair like left/right legs or symmetric arms that should mirror in opposite directions.

output_aThe first servo’s output pin, e.g. o1.
output_bThe second servo’s output pin, e.g. o2 — must be different from output_a.
Example 1 — o1 moves to 30° while o2 automatically moves to 150°.
setup:
    servo_sync_reverse(o1, o2)
loop:
    o1 = servo_angle(30)
Example 2 — o2 sweeps the mirror-image range (60–90–120’s opposite) as o1 oscillates.
setup:
    servo_sync_reverse(o1, o2)
loop:
    servo_oscillate(o1, 90, 60, 120, 5, 20)
Example 3 — Links the two servos to move opposite each other only once the button has been pressed.
if i1 == ON:
    servo_sync_reverse(o1, o2)

Output Function

<output> = <value>

Sets a PWM output to a value from 0–100.

outputAn output pin, e.g. o1, or an alias for one.
value0–100 (percent power). Out-of-range values are clamped automatically.
Example 1 — Full power to o1.
o1 = pwm(100)
Example 2 — Half power — good for dimming an LED.
o1 = pwm(50)
Example 3 — You can assign a variable’s value too, not just a number.
count = 75
o1 = count
<output> = invert(<pin>)

The opposite ON / OFF of a digital pin: ON when that pin is OFF, OFF when it is ON. Digital pins only — not a pwm(), servo, buzzer, RGB or analog pin. Reading an output (invert(o2)) needs board firmware 2.26; an input follows its wiring (active_low / active_high). For a variable, use not x.

pinA digital pin or its name: an output like o2, or an input like i1.
Example 1 — o1 is always the opposite of o2 — one LED on, the other off.
o1 = invert(o2)
Example 2 — The LED is ON until the button is pressed, then OFF.
o1 = invert(i1)
output_increment(output, step, max_value, step_delay)

Increases a general output value once, by a fixed step — never past max_value.

outputAn output pin, e.g. o1.
stepHow much to increase by.
max_valueWon’t go above this, even if the step would push it further (0–100).
step_delayHow long the move takes, in milliseconds.
Example 1 — Raises o1 by 10, taking 200ms, capped at 100.
output_increment(o1, 10, 100, 200)
Example 2 — Ramps up in steps of 20, but stops climbing once it hits 80 — even if called again.
repeat(5):
    output_increment(o1, 20, 80, 100)
Example 3 — Nudges the value up a little every press, capped at 90.
if i1 == ON:
    output_increment(o1, 5, 90, 50)
output_decrement(output, step, min_value, step_delay)

Decreases a general output value once, by a fixed step — never below min_value.

outputAn output pin, e.g. o1.
stepHow much to decrease by.
min_valueWon’t go below this, even if the step would push it further (0–100).
step_delayHow long the move takes, in milliseconds.
Example 1 — Lowers o1 by 10, taking 200ms, capped at 0.
output_decrement(o1, 10, 0, 200)
Example 2 — Ramps down in steps of 20, but stops descending once it hits 20.
repeat(5):
    output_decrement(o1, 20, 20, 100)
Example 3 — A second button nudges the value back down, capped at 10.
if i2 == ON:
    output_decrement(o1, 5, 10, 50)
output_increment_till(output, start_value, end_value, step, step_delay)

Jumps to start_value, then climbs step by step up to end_value.

outputAn output pin, e.g. o1.
start_valueWhere it begins — set immediately, before the climb starts (0–100).
end_valueWhere it stops. If this isn’t above start_value, nothing happens.
stepHow much to increase by each move.
step_delayMilliseconds to pause between steps.
Example 1 — Starts at 0, climbs to 100, 5 at a time — a smooth fade-in.
output_increment_till(o1, 0, 100, 5, 50)
Example 2 — Ramps a fan or LED from 20% up to 80%.
output_increment_till(o1, 20, 80, 10, 30)
Example 3 — Only climbs while the button is held, always starting from 20.
if i1 == ON:
    output_increment_till(o1, 20, 100, 10, 20)
output_decrement_till(output, start_value, end_value, step, step_delay)

Jumps to start_value, then descends step by step down to end_value.

outputAn output pin, e.g. o1.
start_valueWhere it begins — set immediately, before the descent starts (0–100).
end_valueWhere it stops. If this isn’t below start_value, nothing happens.
stepHow much to decrease by each move.
step_delayMilliseconds to pause between steps.
Example 1 — Starts at 100, descends to 0, 5 at a time — a smooth fade-out.
output_decrement_till(o1, 100, 0, 5, 50)
Example 2 — Ramps a fan or LED down from 80% to 20%.
output_decrement_till(o1, 80, 20, 10, 30)
Example 3 — Only descends while a second button is held, always starting from 100.
if i2 == ON:
    output_decrement_till(o1, 100, 20, 10, 20)
output_flip(output, off_value, on_value)

Flips an output between two values each time this line runs: first on_value, then off_value, then on_value again…

outputAn output pin, e.g. o1.
off_valueThe “off” value (0–100), e.g. 0.
on_valueThe “on” value (0–100), e.g. 100 — used the FIRST time the line runs.
Example 1 — Each time this line runs: 100, then 0, then 100, then 0 — a simple on/off flip.
output_flip(o1, 0, 100)
Example 2 — Alternates between 60 and 20 (starting at 60) each time this line runs.
output_flip(o1, 20, 60)
Example 3 — A button press flips the output between fully off and fully on, alternating with each press.
if i1 == ON:
    output_flip(o1, 0, 100)

Ultrasonic Function

distance()
Needs: import ultrasonic

Reads the ultrasonic sensor’s distance in cm. Its pins are fixed (i3/i4 on TinkerPy Mega, i1/i2 on Mini), so no pin is needed.

Example 1 — Turns o1 on when something is closer than 10cm.
d = distance()
if d < 10:
    o1 = pwm(100)
Example 2 — Stores the distance in a variable to use later.
d = distance()
count = d
o1 = pwm(100)
Example 3 — You can call distance() directly inside a condition too.
if distance() > 50:
    o1 = 0
else:
    o1 = pwm(100)

DHT11 Function

dht_temperature(input)
Needs: import dht11

Reads the DHT11 sensor’s temperature in °C.

inputWhich input the DHT11 is wired to, e.g. i3.
Example 1 — Stores the current temperature in a variable.
t = dht_temperature(i3)
Example 2 — Turns on a fan (o1) when it’s hot.
if dht_temperature(i3) > 30:
    o1 = pwm(100)
Example 3 — Turns on a heater (o2) when it’s cold.
t = dht_temperature(i3)
if t < 15:
    o2 = pwm(100)
dht_humidity(input)
Needs: import dht11

Reads the DHT11 sensor’s humidity in %.

inputWhich input the DHT11 is wired to — the same one as dht_temperature.
Example 1 — Stores the current humidity in a variable.
h = dht_humidity(i3)
Example 2 — Turns something on when it’s very humid.
if dht_humidity(i3) > 70:
    o1 = pwm(100)
Example 3 — Turns something on when the air is too dry.
h = dht_humidity(i3)
if h < 30:
    o2 = pwm(100)

MPU6050 Function

tilt_x()
Needs: import mpu6050

How much the front edge (the X arrow on the sensor) is tilted: up = +, down = −, from −90 to 90 degrees.

Example 1 — Shows the front/back tilt on the display.
t = tilt_x()
oled_write(1, left, small, regular, t)
Example 2 — Turns o1 on while the front is tipped down.
if tilt_x() < -20:
    o1 = ON
else:
    o1 = OFF
Example 3 — Sends a message when a lid is lifted past 45°.
if tilt_x() > 45:
    iot_write("Lid is open")
tilt_y()
Needs: import mpu6050

How much it leans sideways: right side down = +, left side down = −, from −90 to 90 degrees.

Example 1 — Turns o2 on when it leans to the right.
if tilt_y() > 20:
    o2 = ON
else:
    o2 = OFF
Example 2 — Shows the sideways tilt on line 2.
t = tilt_y()
oled_write(2, left, small, regular, t)
Example 3 — A "not level" warning light.
if tilt_y() < -20 or tilt_y() > 20:
    o1 = ON
tilt_direction()
Needs: import mpu6050

Which way it is tipped: 'F' forward (front down), 'B' back, 'L' left, 'R' right, or 'N' flat (less than 15°).

Example 1 — A gesture remote: tip forward to drive, hold flat to stop.
d = tilt_direction()
if d == 'F':
    robot_control("F", 80, "F", 80)
elif d == 'N':
    robot_control("S", 0, "S", 0)
Example 2 — Lights o1 while tipped to the left.
if tilt_direction() == 'L':
    o1 = ON
else:
    o1 = OFF
Example 3 — Shows "Level!" when it lies flat.
if tilt_direction() == 'N':
    oled_write(1, left, small, regular, "Level!")
shake_detected()
Needs: import mpu6050

1 once after the sensor is shaken, then 0 until the next shake.

Example 1 — Flashes a light when you shake it.
if shake_detected() == 1:
    o1 = ON
    wait(1000)
    o1 = OFF
Example 2 — Counts the shakes.
if shake_detected() == 1:
    c1.increment()
    oled_write(1, left, small, regular, c1)
Example 3 — Tells the app when it is shaken.
if shake_detected() == 1:
    iot_write("Shaken!")
motion_level()
Needs: import mpu6050

How much it is moving right now, from 0 (still) to 100 (lots of movement).

Example 1 — An anti-theft alarm: o1 goes on when the box is moved.
if motion_level() > 30:
    o1 = ON
else:
    o1 = OFF
Example 2 — Shows the movement level live.
oled_write(1, left, small, regular, motion_level())
Example 3 — The more it moves, the brighter o1 glows.
o1 = motion_level()
fall_detected()
Needs: import mpu6050

1 once after the sensor falls (free fall), then 0.

Example 1 — A fall alarm that also sends a message.
if fall_detected() == 1:
    o1 = ON
    iot_write("Fall detected!")
Example 2 — Shows a message after a drop.
if fall_detected() == 1:
    oled_write(1, left, small, regular, "Oops! I fell")
Example 3 — Counts how many times it was dropped.
if fall_detected() == 1:
    c1.increment()
turn_angle()
Needs: import mpu6050

Degrees it has turned (spun flat, like a robot turning) since reset_turn(): right = +, left = −. It slowly drifts — reset it before each turn.

Example 1 — Turns the robot right until it has turned 90°.
setup:
    reset_turn()
loop:
    robot_control("F", 60, "B", 60)
    repeat(300):
        if turn_angle() >= 90:
            robot_control("S", 0, "S", 0)
        wait(10)
Example 2 — Shows how far it has turned.
oled_write(1, left, small, regular, turn_angle())
Example 3 — Lights o1 after turning 45° to the left.
if turn_angle() < -45:
    o1 = ON
reset_turn()
Needs: import mpu6050

Sets turn_angle() back to 0 — call it just before a turn.

Example 1 — Start counting the turn from here.
setup:
    reset_turn()
Example 2 — A button sets the turn angle back to 0.
if i1 == ON:
    reset_turn()
Example 3 — Shows how much it turned in 2 seconds.
setup:
    reset_turn()
loop:
    wait(2000)
    oled_write(1, left, small, regular, turn_angle())
step_count()
Needs: import mpu6050

How many steps were counted (carry the sensor while walking) since reset_steps().

Example 1 — A simple pedometer.
oled_write(1, left, small, regular, step_count())
Example 2 — Lights o1 after 100 steps.
if step_count() >= 100:
    o1 = ON
Example 3 — Sends a message at 1000 steps.
if step_count() >= 1000:
    iot_write("1000 steps!")
reset_steps()
Needs: import mpu6050

Sets step_count() back to 0.

Example 1 — Start counting steps from 0.
setup:
    reset_steps()
Example 2 — A button resets the step counter.
if i1 == ON:
    reset_steps()
Example 3 — Lights o1 every 50 steps.
if step_count() >= 50:
    o1 = ON
    reset_steps()
accel_x()
Needs: import mpu6050

Raw acceleration along X in 1/100 g (100 = gravity). For older students.

Example 1 — Shows the X acceleration.
oled_write(1, left, small, regular, accel_x())
Example 2 — On when the X axis points well upwards.
a = accel_x()
if a > 50:
    o1 = ON
Example 3 — Use it with the display while testing.
iot_write("x")
oled_write(2, left, small, regular, accel_x())
accel_y()
Needs: import mpu6050

Raw acceleration along Y in 1/100 g (100 = gravity).

Example 1 — Shows the Y acceleration.
oled_write(2, left, small, regular, accel_y())
Example 2 — On when the Y axis points well downwards.
if accel_y() < -50:
    o1 = ON
Example 3 — Stores it in a variable first.
a = accel_y()
oled_write(1, left, small, regular, a)
accel_z()
Needs: import mpu6050

Raw acceleration along Z in 1/100 g — about 100 when lying flat, about −100 upside down.

Example 1 — On when the sensor is upside down.
if accel_z() < 0:
    o1 = ON
Example 2 — Shows the Z acceleration.
oled_write(3, left, small, regular, accel_z())
Example 3 — Says "Flat" when it lies level.
if accel_z() > 90:
    oled_write(1, left, small, regular, "Flat")
gyro_x()
Needs: import mpu6050

How fast it rotates around X, in degrees per second.

Example 1 — Shows the rotation speed around X.
oled_write(1, left, small, regular, gyro_x())
Example 2 — On while it is flipped forward quickly.
if gyro_x() > 100:
    o1 = ON
Example 3 — Stores it in a variable first.
g = gyro_x()
oled_write(2, left, small, regular, g)
gyro_y()
Needs: import mpu6050

How fast it rotates around Y, in degrees per second.

Example 1 — Shows the rotation speed around Y.
oled_write(1, left, small, regular, gyro_y())
Example 2 — On while it is rolled quickly to one side.
if gyro_y() < -100:
    o1 = ON
Example 3 — Stores it in a variable first.
g = gyro_y()
oled_write(2, left, small, regular, g)
gyro_z()
Needs: import mpu6050

How fast it spins flat (around Z), in degrees per second.

Example 1 — On while it is spun quickly.
if gyro_z() > 100:
    o1 = ON
else:
    o1 = OFF
Example 2 — Shows the spin speed.
oled_write(1, left, small, regular, gyro_z())
Example 3 — Tells the app when it spins fast either way.
if gyro_z() > 200 or gyro_z() < -200:
    iot_write("Spinning!")
mpu_temperature()
Needs: import mpu6050

The temperature of the MPU6050 chip in °C (a little warmer than the room).

Example 1 — Shows the chip temperature.
oled_write(1, left, small, regular, mpu_temperature())
Example 2 — A "too warm" light.
if mpu_temperature() > 40:
    o1 = ON
Example 3 — Stores it in a variable first.
t = mpu_temperature()
oled_write(2, left, small, regular, t)

RTC Clock Function

A real-time clock module (any DS3231 or DS1307) on o7 (SDA) / o8 (SCL). It keeps the time with its own small battery, even when the board is off. Set it once with rtc_set_time / rtc_set_date in setup: — the board sets the clock only when that new code arrives, not at every power-on. Address 0x68 (same as the MPU6050 — use one of them). Use a 3.3 V DS3231 board: “Tiny RTC” DS1307 boards need 5 V and put 5 V on the I2C wires, which the board’s pins can’t take.

rtc_hour()
Needs: import rtc · Firmware: 2.27+

The hour from the RTC clock module, 0 to 23 (2 PM = 14). The module keeps time even when the board is off (it has a small battery).

Example 1 — Shows the hour.
h = rtc_hour()
oled_write(1, left, small, regular, h)
Example 2 — A light that comes on at 6 PM.
if rtc_hour() >= 18:
    o1 = ON
else:
    o1 = OFF
Example 3 — A 7:00 alarm.
if rtc_hour() == 7 and rtc_minute() == 0:
    buzzer_play(o2, "school_bell")
rtc_minute()
Needs: import rtc · Firmware: 2.27+

The minute from the RTC clock, 0 to 59.

Example 1 — Shows the minute.
oled_write(2, left, small, regular, rtc_minute())
Example 2 — Turns o1 on at half past every hour.
if rtc_minute() == 30:
    o1 = ON
Example 3 — o2 is on for the first 10 minutes of each hour.
m = rtc_minute()
if m < 10:
    o2 = ON
rtc_second()
Needs: import rtc · Firmware: 2.27+

The second from the RTC clock, 0 to 59.

Example 1 — Shows the seconds ticking.
oled_write(3, left, small, regular, rtc_second())
Example 2 — Blinks o1 with the clock: on for even seconds.
if rtc_second() % 2 == 0:
    o1 = ON
else:
    o1 = OFF
Example 3 — A short blink at the start of every minute.
if rtc_second() == 0:
    o2 = ON
    wait(200)
    o2 = OFF
rtc_day()
Needs: import rtc · Firmware: 2.27+

The day of the month, 1 to 31.

Example 1 — Shows the date.
oled_write(1, left, small, regular, rtc_day())
Example 2 — A first-of-the-month reminder light.
if rtc_day() == 1:
    o1 = ON
Example 3 — Keeps the day in a variable.
d = rtc_day()
m = rtc_month()
oled_write(2, left, small, regular, d)
rtc_month()
Needs: import rtc · Firmware: 2.27+

The month, 1 (January) to 12 (December).

Example 1 — Shows the month number.
oled_write(2, left, small, regular, rtc_month())
Example 2 — Something special on 25 December.
if rtc_month() == 12 and rtc_day() == 25:
    rgb_color(o1, all, "red", 80)
Example 3 — A summer-holiday light in April and May.
if rtc_month() >= 4 and rtc_month() <= 5:
    o1 = ON
rtc_year()
Needs: import rtc · Firmware: 2.27+

The year, like 2026.

Example 1 — Shows the year.
oled_write(3, left, small, regular, rtc_year())
Example 2 — Keeps the year in a variable.
y = rtc_year()
oled_write(1, left, small, regular, y)
Example 3 — A hint when the clock was never set.
if rtc_year() < 2026:
    oled_write(2, left, small, regular, "Set the clock")
rtc_weekday()
Needs: import rtc · Firmware: 2.27+

The day of the week: 1 Monday, 2 Tuesday … 6 Saturday, 7 Sunday.

Example 1 — No school bell on Saturday and Sunday.
if rtc_weekday() >= 6:
    o1 = OFF
Example 2 — Shows the day number.
d = rtc_weekday()
oled_write(4, left, small, regular, d)
Example 3 — Monday morning reminder.
if rtc_weekday() == 1 and rtc_hour() == 8:
    o1 = ON
rtc_set_time(hour, minute, second)
Needs: import rtc · Firmware: 2.27+

Sets the RTC clock's time. Put it in setup: — the board sets the clock ONCE when this new code reaches it (not again at every power-on), so the clock keeps running from there. To set it again, change the numbers and upload again.

hour0-23
minute0-59
second0-59
Example 1 — Sets the clock to 2:05:00 PM once, then shows the minute.
setup:
    rtc_set_time(14, 5, 0)
loop:
    oled_write(1, left, small, regular, rtc_minute())
Example 2 — Sets 7:30 in the morning.
setup:
    rtc_set_time(7, 30, 0)
Example 3 — Midnight, to test the date changing.
setup:
    rtc_set_time(0, 0, 0)
    rtc_set_date(31, 12, 2026)
rtc_set_date(day, month, year)
Needs: import rtc · Firmware: 2.27+

Sets the RTC clock's date, once when the new code reaches the board (like rtc_set_time). The year can be 2026 or 26.

day1-31
month1-12
year2000-2099 (or 0-99)
Example 1 — Sets 16 October 2026 and the time.
setup:
    rtc_set_date(16, 10, 2026)
    rtc_set_time(9, 0, 0)
Example 2 — The year can be written as 27.
setup:
    rtc_set_date(1, 1, 27)
Example 3 — 29 February works in a leap year.
setup:
    rtc_set_date(29, 2, 2028)

Pulse Oximeter Function

A pulse oximeter module (any MAX30100 or MAX30102) on o7 / o8, address 0x57. Rest a fingertip gently on it and keep still; the first numbers come after a few seconds. For learning only — not a medical device. A MAX30102 board is the easy choice; green GY-MAX30100 boards pull the I2C wires to 1.8 V and may not work.

heart_rate()
Needs: import pulse_oximeter · Firmware: 2.27+

Heart beats a minute from the finger on the sensor, or 0 when there is no finger (or it is still measuring — it takes a few seconds). For learning only, not for medical use.

Example 1 — Shows the heart rate.
oled_write(1, left, small, regular, heart_rate())
Example 2 — A light when the heart beats fast, e.g. after running.
if heart_rate() > 100:
    o1 = ON
else:
    o1 = OFF
Example 3 — A slow-heart light (0 means no finger).
b = heart_rate()
if b > 0 and b < 60:
    o2 = ON
spo2()
Needs: import pulse_oximeter · Firmware: 2.27+

How much oxygen the blood carries, in % (usually 95-100), or 0 when there is no finger. For learning only.

Example 1 — Shows the oxygen %.
oled_write(2, left, small, regular, spo2())
Example 2 — A low-oxygen warning light.
if finger_detected() == 1 and spo2() < 94:
    o2 = ON
Example 3 — Keeps the oxygen % in a variable.
s = spo2()
oled_write(3, left, small, regular, s)
finger_detected()
Needs: import pulse_oximeter · Firmware: 2.27+

1 while a finger is on the sensor, else 0.

Example 1 — Asks for a finger.
if finger_detected() == 0:
    oled_write(1, left, small, regular, "Put a finger on")
Example 2 — A light while a finger is on.
if finger_detected() == 1:
    o1 = ON
else:
    o1 = OFF
Example 3 — Shows the heart rate only with a finger on.
if finger_detected() == 1:
    oled_write(1, left, small, regular, heart_rate())
heart_beat()
Needs: import pulse_oximeter · Firmware: 2.27+

1 for one loop at every heart beat, else 0 — use it to blink or beep with the heart.

Example 1 — Blinks o1 with each beat.
if heart_beat() == 1:
    o1 = ON
    wait(100)
    o1 = OFF
Example 2 — Beeps with each beat.
if heart_beat() == 1:
    buzzer_play(o2, "beep")
Example 3 — An RGB LED that glows with each beat.
if heart_beat() == 1:
    rgb_color(o1, all, "red", 80)
else:
    rgb_color(o1, all, "red", 5)

BMP280 Function

A BMP280 (or BME280) air-pressure module on o7 / o8, address 0x76 or 0x77.

pressure()
Needs: import bmp280 · Firmware: 2.27+

The air pressure in hPa (about 1013 at sea level, lower up a hill).

Example 1 — Shows the air pressure.
oled_write(1, left, small, regular, pressure())
Example 2 — A "rain may come" light when the pressure falls.
if pressure() < 1000:
    o1 = ON
Example 3 — A fine-weather light when the pressure is high.
p = pressure()
if p > 1020:
    o2 = ON
bmp_temperature()
Needs: import bmp280 · Firmware: 2.27+

The temperature from the BMP280 in °C.

Example 1 — Shows the temperature.
oled_write(2, left, small, regular, bmp_temperature())
Example 2 — Switches a fan on when it is hot.
if bmp_temperature() > 35:
    o2 = ON
else:
    o2 = OFF
Example 3 — Keeps the temperature in a variable.
t = bmp_temperature()
oled_write(3, left, small, regular, t)
altitude()
Needs: import bmp280 · Firmware: 2.27+

How high you are above the sea in metres, worked out from the air pressure (it changes a little with the weather).

Example 1 — Shows the height above sea level.
oled_write(3, left, small, regular, altitude())
Example 2 — Lights o1 when carried up 3 metres (a floor of a building).
start = altitude()
if altitude() > start + 3:
    o1 = ON
Example 3 — A light up in the hills.
if altitude() > 900:
    o1 = ON

Laser Distance Function

A VL53L0X laser distance (time-of-flight) sensor on o7 / o8, address 0x29: 3 cm to about 2 m, more exact than ultrasonic. 999 = nothing in range. It shares 0x29 with the TCS34725 — use one of them (for colour too, use an APDS-9960).

laser_distance()
Needs: import vl53l0x · Firmware: 2.27+

The distance to the object in front of the laser sensor, in cm (3 to about 200). 999 = nothing in range. More exact than ultrasonic, and works on soft things too.

Example 1 — Shows the distance.
oled_write(1, left, small, regular, laser_distance())
Example 2 — Something close? Light on.
if laser_distance() < 15:
    o1 = ON
else:
    o1 = OFF
Example 3 — Parking help: o1 (red) on when closer than 30 cm.
d = laser_distance()
if d < 30:
    o1 = ON
    o2 = OFF

Colour Sensor Function

A TCS34725 colour sensor (address 0x29) or an APDS-9960 (0x39) on o7 / o8. Hold the colour 1–2 cm from it with its light on. color_name() gives one of: "red" "orange" "yellow" "green" "blue" "purple" "pink" "white" "black".

color_name()
Needs: import tcs34725 or import apds9960 · Firmware: 2.27+

The colour in front of the sensor — compare it with a colour name: "red" "orange" "yellow" "green" "blue" "purple" "pink" "white" "black".

Example 1 — Lights o1 for red.
if color_name() == "red":
    o1 = ON
else:
    o1 = OFF
Example 2 — A colour sorter: green one way, blue the other.
c = color_name()
if c == "green":
    o2 = servo_angle(90)
elif c == "blue":
    o2 = servo_angle(0)
Example 3 — A line follower idea: black or not.
if color_name() == "black":
    o1 = OFF
else:
    o1 = ON
color_red()
Needs: import tcs34725 or import apds9960 · Firmware: 2.27+

How much red the sensor sees, 0-255 (the strongest colour is always 255).

Example 1 — Shows the red amount.
oled_write(1, left, small, regular, color_red())
Example 2 — Copies the colour it sees onto an RGB LED.
rgb_hex_color(o1, all, color_red(), color_green(), color_blue())
Example 3 — Red seen: lots of red, little green.
if color_red() == 255 and color_green() < 100:
    o1 = ON
color_green()
Needs: import tcs34725 or import apds9960 · Firmware: 2.27+

How much green the sensor sees, 0-255.

Example 1 — Shows the green amount.
oled_write(2, left, small, regular, color_green())
Example 2 — Green is the strongest colour.
if color_green() == 255:
    o2 = ON
else:
    o2 = OFF
Example 3 — Keeps it in a variable.
g = color_green()
oled_write(4, left, small, regular, g)
color_blue()
Needs: import tcs34725 or import apds9960 · Firmware: 2.27+

How much blue the sensor sees, 0-255.

Example 1 — Shows the blue amount.
oled_write(3, left, small, regular, color_blue())
Example 2 — Lots of blue.
if color_blue() > 200:
    o3 = ON
Example 3 — Keeps it in a variable.
b = color_blue()
oled_write(4, left, small, regular, b)
color_brightness()
Needs: import tcs34725 or import apds9960 · Firmware: 2.27+

How much light comes back to the colour sensor, 0-100 (dark = small).

Example 1 — A light when it gets dark (or something black is in front).
if color_brightness() < 10:
    o1 = ON
Example 2 — Shows the brightness.
oled_write(1, left, small, regular, color_brightness())
Example 3 — Something white or shiny in front.
if color_brightness() > 80:
    o2 = ON

Gesture Function

An APDS-9960 gesture sensor on o7 / o8, address 0x39. Swipe a hand 5–10 cm above it. Each swipe is seen in ONE pass of loop: (then None). It is also a colour sensor (the colour functions above).

gesture()
Needs: import apds9960 · Firmware: 2.27+

The hand swipe just made over the sensor: compare it with "up" "down" "left" "right". It gives None when there is no new swipe — each swipe is seen in ONE loop.

Example 1 — Swipe left = light on, right = off.
if gesture() == "left":
    o1 = ON
elif gesture() == "right":
    o1 = OFF
Example 2 — Counts up and down with swipes (import counter).
g = gesture()
if g == "up":
    c1.increment()
elif g == "down":
    c1.decrement()
Example 3 — Swipe up / down to open and close a lid.
if gesture() == "up":
    o1 = servo_angle(180)
elif gesture() == "down":
    o1 = servo_angle(0)
proximity()
Needs: import apds9960 · Firmware: 2.27+

How near a hand (or object) is to the sensor: 0 far away … 100 very close (about 10 cm range).

Example 1 — Shows how near your hand is.
oled_write(1, left, small, regular, proximity())
Example 2 — A touch-free switch: wave close to turn it on.
if proximity() > 60:
    o1 = ON
else:
    o1 = OFF
Example 3 — Keeps it in a variable.
p = proximity()
oled_write(2, left, small, regular, p)

GPS Function

A GPS module (NEO-6M or similar, 9600 baud) — its TX wire goes to ANY pin, set in setup: as gps_rx: i1 = set_input(gps_rx) (TinkerPy Code adds the line on Compile, named gps_rx_1). Outdoors it needs about a minute to find satellites. Firmware 2.28.

gps_found()
Needs: import gps · Firmware: 2.28+

1 when the GPS knows where it is (it has a fix), else 0. Outdoors it takes about a minute after power-on.

Example 1 — A light that shows the GPS is ready.
if gps_found() == 1:
    o1 = ON
else:
    o1 = OFF
Example 2 — Tells you to wait.
if gps_found() == 0:
    oled_write(1, left, small, regular, "Searching...")
Example 3 — Keeps it in a variable.
f = gps_found()
oled_write(2, left, small, regular, f)
gps_satellites()
Needs: import gps · Firmware: 2.28+

How many satellites the GPS can see (4 or more is good).

Example 1 — Shows the satellites.
oled_write(1, left, small, regular, gps_satellites())
Example 2 — A weak-signal light.
if gps_satellites() < 4:
    o2 = ON
Example 3 — Sends it to the app (import bluetooth).
s = gps_satellites()
bluetooth_write(s)
gps_speed()
Needs: import gps · Firmware: 2.28+

How fast it is moving, in km/h.

Example 1 — A speedometer.
oled_write(1, left, small, regular, gps_speed())
Example 2 — Beeps when going faster than 40 km/h.
if gps_speed() > 40:
    buzzer_play(o2, "beep")
Example 3 — A "stopped" light.
s = gps_speed()
if s == 0:
    o1 = ON
gps_altitude()
Needs: import gps · Firmware: 2.28+

Height above the sea in metres.

Example 1 — Shows the height.
oled_write(2, left, small, regular, gps_altitude())
Example 2 — On high ground.
if gps_altitude() > 500:
    o1 = ON
Example 3 — Sends it over IoT.
a = gps_altitude()
iot_write(a)
gps_hour()
Needs: import gps · Firmware: 2.28+

The hour from the satellites, in Indian time (0–23). Very exact — no clock to set.

Example 1 — Shows the hour.
oled_write(1, left, small, regular, gps_hour())
Example 2 — A light from 6 PM.
if gps_hour() >= 18:
    o1 = ON
Example 3 — Keeps the time in variables.
h = gps_hour()
m = gps_minute()
oled_write(2, left, small, regular, h)
gps_minute()
Needs: import gps · Firmware: 2.28+

The minute from the satellites, 0–59.

Example 1 — Shows the minute.
oled_write(2, left, small, regular, gps_minute())
Example 2 — A 7:00 alarm.
if gps_hour() == 7 and gps_minute() == 0:
    o1 = ON
Example 3 — On for the first 5 minutes of each hour.
m = gps_minute()
if m < 5:
    o2 = ON
gps_second()
Needs: import gps · Firmware: 2.28+

The second from the satellites, 0–59.

Example 1 — Shows the seconds.
oled_write(3, left, small, regular, gps_second())
Example 2 — Blinks with the satellite clock.
if gps_second() % 2 == 0:
    o1 = ON
else:
    o1 = OFF
Example 3 — Keeps it in a variable.
s = gps_second()
oled_write(4, left, small, regular, s)
gps_save_home()
Needs: import gps · Firmware: 2.28+

Remembers where it is now as "home" (put it in setup:). If the GPS has no fix yet, home is saved as soon as it finds one.

Example 1 — Saves home (write it in setup:).
gps_save_home()
Example 2 — Press a button to save a new home.
if i1 == ON:
    gps_save_home()
Example 3 — Saves home and says so.
gps_save_home()
oled_write(1, left, small, regular, "Home saved")
gps_distance_home()
Needs: import gps · Firmware: 2.28+

How many metres it is from home (gps_save_home()). 0 until home is saved and the GPS has a fix.

Example 1 — Shows the distance from home.
oled_write(1, left, small, regular, gps_distance_home())
Example 2 — A geofence: alarm when it goes more than 100 m away.
if gps_distance_home() > 100:
    buzzer_play(o2, "alarm")
Example 3 — A "you are home" light.
d = gps_distance_home()
if d < 10:
    o1 = ON
gps_location()
Needs: import gps · Firmware: 2.28+

Where it is, as text: "12.91416,74.85603" (latitude,longitude — paste it into Google Maps). Empty text (None) until the GPS has a fix. Show it, store it or send it by SMS / Bluetooth / IoT.

Example 1 — Shows the position on the OLED.
oled_write(1, left, small, regular, gps_location())
Example 2 — Sends it to the app (import bluetooth).
loc = gps_location()
bluetooth_write(loc)
Example 3 — An SOS button: sends the position by SMS (import gsm).
if i1 == ON:
    gsm_send_sms("+919876543210", "Help! I am at " + gps_location())

GSM Function

A SIM800L GSM module with a SIM card — its TX wire goes to a pin set as gsm_rx (any pin) and its RX wire to an output set as gsm_tx: i2 = set_input(gsm_rx), o5 = set_output(gsm_tx). It needs its own 4 V, 2 A power supply (not the board's 3.3 V or 5 V pin), with the grounds joined. Messages are up to 30 letters. The same SMS is sent once in 5 minutes, at most one SMS every 10 seconds. Firmware 2.28.

gsm_send_sms("number", message)
Needs: import gsm · Firmware: 2.28+

Sends an SMS. The number in quotes (with +91 if you like), the message is text, a number or a join like "Temp " + t (up to 30 letters). The same SMS is not sent again for 5 minutes, and at most one SMS every 10 seconds — SMS cost money.

numberThe phone number in quotes, e.g. "+919876543210" — or gsm_sms_number() to reply.
messageText, a number, a text variable or a join.
Example 1 — An alarm SMS when the door opens.
if i1 == ON:
    gsm_send_sms("+919876543210", "Door open")
Example 2 — Sends the temperature when it is too hot.
t = dht_temperature(i3)
if t > 40:
    gsm_send_sms("+919876543210", "Too hot: " + t)
Example 3 — Replies to whoever sent STATUS.
if gsm_read_sms() == "STATUS":
    gsm_send_sms(gsm_sms_number(), "All OK")
gsm_sms_received()
Needs: import gsm · Firmware: 2.28+

1 for one loop when an SMS arrives, else 0.

Example 1 — Beeps for every SMS.
if gsm_sms_received() == 1:
    buzzer_play(o2, "beep")
Example 2 — Shows each new SMS.
if gsm_sms_received() == 1:
    oled_write(1, left, small, regular, gsm_read_sms())
Example 3 — Counts the SMS (import counter).
if gsm_sms_received() == 1:
    c1.increment()
gsm_read_sms()
Needs: import gsm · Firmware: 2.28+

The text of the SMS that just arrived (for one loop), or None. Compare it: gsm_read_sms() == "ON" (capitals count).

Example 1 — Switch a pump or a light by SMS.
if gsm_read_sms() == "ON":
    o1 = ON
elif gsm_read_sms() == "OFF":
    o1 = OFF
Example 2 — Keeps the last SMS on the screen.
msg = gsm_read_sms()
if msg != None:
    oled_write(2, left, small, regular, msg)
Example 3 — Texts back the GPS position (import gps).
if gsm_read_sms() == "WHERE":
    gsm_send_sms(gsm_sms_number(), gps_location())
gsm_sms_number()
Needs: import gsm · Firmware: 2.28+

Who sent the SMS that just arrived (their number, as text) — use it to reply.

Example 1 — Replies to every SMS.
if gsm_sms_received() == 1:
    gsm_send_sms(gsm_sms_number(), "Got it")
Example 2 — Only Mum's phone can switch it on.
if gsm_sms_number() == "+919876543210":
    o1 = ON
Example 3 — Shows who sent it.
n = gsm_sms_number()
oled_write(1, left, small, regular, n)
gsm_call("number")
Needs: import gsm · Firmware: 2.28+

Calls a phone. The same number is not called again for 30 seconds.

numberThe phone number in quotes, or gsm_sms_number().
Example 1 — A call button.
if i1 == ON:
    gsm_call("+919876543210")
Example 2 — Calls when there is gas (import gas sensor on i2).
if analog_read(i2) > 70:
    gsm_call("+919876543210")
Example 3 — Calls back whoever asked.
if gsm_read_sms() == "CALL ME":
    gsm_call(gsm_sms_number())
gsm_hang_up()
Needs: import gsm · Firmware: 2.28+

Ends a call, or stops a phone that is ringing.

Example 1 — Rejects every call.
if gsm_ringing() == 1:
    gsm_hang_up()
Example 2 — A hang-up button.
if i2 == ON:
    gsm_hang_up()
Example 3 — Rings for 20 seconds, then stops.
gsm_call("+919876543210")
wait(20000)
gsm_hang_up()
gsm_ringing()
Needs: import gsm · Firmware: 2.28+

1 while someone is calling the board, else 0.

Example 1 — A light while the board's phone rings.
if gsm_ringing() == 1:
    o1 = ON
else:
    o1 = OFF
Example 2 — Missed-call switch: call the board to turn o2 on.
if gsm_ringing() == 1:
    o2 = ON
    gsm_hang_up()
Example 3 — Shows it.
r = gsm_ringing()
oled_write(1, left, small, regular, r)
gsm_signal()
Needs: import gsm · Firmware: 2.28+

The mobile signal, 0 (none) to 100 (full).

Example 1 — Shows the signal.
oled_write(1, left, small, regular, gsm_signal())
Example 2 — A weak-signal light.
if gsm_signal() < 20:
    o2 = ON
Example 3 — Sends it to the app (import bluetooth).
s = gsm_signal()
bluetooth_write(s)

Buzzer Function

buzzer_play(output, "tone")
Needs: import buzzer · Firmware: 2.19+

Plays a tone or a song on the buzzer; the next line runs when it ends. Simple: beep, double_beep, triple_beep, long_beep, chirp_up, chirp_down, success, error, notify, start_up. Alerts: warning, alarm, ambulance, police, fire_truck, school_bell, school_long_bell, door_bell, countdown, quiz_wrong, phone_ring, marimba_ring, message_beep, retro_phone. Tunes: happy_birthday, jingle_bells, jana_gana_mana, twinkle_twinkle, ode_to_joy, mary_lamb, old_macdonald, merry_christmas. Tunes need a PASSIVE buzzer (an active one just beeps the rhythm). Listen to them all on the board: Menu > Buzzer Tones.

outputThe pin the buzzer is on, e.g. o1.
toneWhich tone or song, in quotes, e.g. "school_bell".
Example 1 — A door bell: press the button, hear ding-dong.
if i1 == ON:
    buzzer_play(o1, "door_bell")
Example 2 — The school bell at 9 o’clock.
setup:
    clock_start(8, 59, 50)
loop:
    if HH == 9 and MM == 0 and SS == 0:
        buzzer_play(o1, "school_long_bell")
Example 3 — Happy birthday on a passive buzzer, then a 3 second rest.
setup:
    o2 = set_function(passive_buzzer)
buzzer_play(o2, "happy_birthday")
wait(3000)
buzzer_play_background(output, "tone", repeat)
Needs: import buzzer · Firmware: 2.29+ · TinkerPy Mega

Starts a tone or song and the program goes on at once (it does not wait). repeat is optional: 1 (or 0) = once, 3 = three times with a 0.5 s gap. If the same tone is already playing on that buzzer it just keeps playing, so you can call it on every pass of loop: for an alarm that sounds while something is true; a different tone stops the old one. One tune plays at a time on the board. Same tones as buzzer_play. TinkerPy Mega, board firmware 2.29.

outputThe pin the buzzer is on, e.g. buzzer (or o1).
toneWhich tone or song, in quotes, e.g. "alarm".
repeatOptional: how many times to play it (0 or 1 = once). 0.5 s between the plays.
Example 1 — An alarm that keeps sounding while i1 is ON — and the program keeps checking.
o1 = set_name("buzzer")
loop:
    if i1 == ON:
        buzzer_play_background(buzzer, "alarm")
Example 2 — Plays "police" 3 times while the light still follows the button at once.
o1 = set_name("buzzer")
loop:
    if i2 == ON:
        buzzer_play_background(buzzer, "police", 3)
    o2 = i2
Example 3 — A birthday song at power-on on a passive buzzer, while the button works straight away.
o1 = set_name("buzzer")
setup:
    buzzer = set_function(passive_buzzer)
    buzzer_play_background(buzzer, "happy_birthday")
loop:
    o2 = i1
buzzer_stop_background(output)
Needs: import buzzer · Firmware: 2.29+ · TinkerPy Mega

Stops the tone that buzzer_play_background started on that buzzer. Nothing happens if it is quiet. TinkerPy Mega, board firmware 2.29.

outputThe pin the buzzer is on, e.g. buzzer (or o1).
Example 1 — The alarm sounds while i1 is ON and stops as soon as it is OFF.
o1 = set_name("buzzer")
loop:
    if i1 == ON:
        buzzer_play_background(buzzer, "alarm")
    else:
        buzzer_stop_background(buzzer)
Example 2 — A silence button on i2.
o1 = set_name("buzzer")
loop:
    if i2 == ON:
        buzzer_stop_background(buzzer)
Example 3 — A siren for 10 seconds at power-on, then quiet.
o1 = set_name("buzzer")
setup:
    buzzer_play_background(buzzer, "police", 100)
    wait(10000)
    buzzer_stop_background(buzzer)
is_buzzer_playing(output)
Needs: import buzzer · Firmware: 2.29+ · TinkerPy Mega

Gives 1 while a tune started by buzzer_play_background is still playing on that buzzer, 0 when it is quiet. (buzzer_play makes the program wait until its tune ends, so after it this gives 0.) TinkerPy Mega, board firmware 2.29.

outputThe pin the buzzer is on, e.g. buzzer (or o1).
Example 1 — A light that is ON while the bell rings.
o1 = set_name("buzzer")
loop:
    if i1 == ON:
        buzzer_play_background(buzzer, "school_bell", 2)
    if is_buzzer_playing(buzzer) == 1:
        o2 = ON
    else:
        o2 = OFF
Example 2 — When the song ends: 2 seconds of quiet, then it plays again.
o1 = set_name("buzzer")
loop:
    if is_buzzer_playing(buzzer) == 0:
        wait(2000)
        buzzer_play_background(buzzer, "twinkle_twinkle")
Example 3 — A light blinks while the song plays, then stays off.
o1 = set_name("buzzer")
setup:
    buzzer = set_function(passive_buzzer)
    buzzer_play_background(buzzer, "jingle_bells")
loop:
    if is_buzzer_playing(buzzer) == 1:
        o2 = ON
        wait(200)
        o2 = OFF
        wait(200)

TV Remote Function

Keys (always in small letters, in quotes): "1"…"9" "0" · "a" "b" "c" "d" (red, green, yellow, blue) · "up" "down" "left" "right" "ok" · "v+" "v-" "ch+" "ch-" · "play" "pause" "ff" "fb" · "menu" "exit". The old keys F B L R S / back / home are gone (Compile changes them).

remote_read()
Needs: import tv_remote · Firmware: 2.23+

The remote key pressed — for one loop, and again and again while it is held. None when no key. Learn the keys on the board first: Menu > TV Remote > Learn Remote.

Example 1 — Drives a robot with the TV remote: up forward, down back, ok stop.
k = remote_read()
if k == "up":
    robot_control("F", 80, "F", 80)
elif k == "down":
    robot_control("B", 80, "B", 80)
elif k == "ok":
    robot_control("S", 0, "S", 0)
Example 2 — Key 1 turns the light on, key 0 turns it off.
k = remote_read()
if k == "1":
    o1 = ON
elif k == "0":
    o1 = OFF
Example 3 — CH+ / CH- turn a light on and off.
if remote_read() == "ch+":
    o1 = ON
if remote_read() == "ch-":
    o1 = OFF
remote_read_string(count, start, display, visibility, seconds)
Needs: import tv_remote · Firmware: 2.23+

Waits for a code typed on the TV remote (keys 0–9 and A–D) and gives it, or 0 when no code was typed. count 1–6 keys · start the key that starts typing (e.g. "menu"; "any" or 0 = start straight away) · display "oled" (board screen: Enter Code, _ _ _, countdown), "lcd" (needs lcd_begin), an output like o1 (blinks 1× for the 1st key, 2× for the 2nd …) or 0 (nothing shown) · visibility "visible" (3 4 _) or "invisible" (each key shows for a moment, then *) · seconds 1–255 for the whole code. When the start key is not pressed it gives 0 at once (the loop carries on). After the last key the code stays on the display for 2 seconds. exit cancels. Store it in a variable and compare it in quotes: if code == "48A": (or code != 0 = any code). A code can’t be shown with oled_write.

Example 1 — A door lock: press menu, type 4 8 2 on the remote, and the servo opens.
code = remote_read_string(3, "menu", "oled", "visible", 10)
if code == "482":
    o1 = servo_angle(90)
Example 2 — A secret 4-key code on the LCD, shown as * — right code lights o2, wrong code o3.
code = remote_read_string(4, "any", "lcd", "invisible", 15)
if code == "12AB":
    o2 = ON
elif code != 0:
    o3 = ON
Example 3 — No display: o1 blinks once for the 1st key, twice for the 2nd.
setup:
    o1 = set_function(output)
code = remote_read_string(2, "ok", o1, "visible", 9)
if code == "77":
    o2 = ON

Wireless Function

Board to board, no wires (ESP-NOW, firmware 2.24, TinkerPy Mega). Write the other board’s Device ID (TP and 8 numbers, on that board: Menu → Device info) before the dot: TP00000002.send("ON"). Compile looks each board up on tinkerpy.com (the student must be online; an unknown ID is an error). A link opens only when both boards’ programs list each other — and connect() each other in setup: — so a stranger’s board can’t disturb yours. Up to 6 boards; the link comes back by itself. A message is up to 30 characters and is there for one loop. The board screen header shows LK: OK; Menu → Wireless devices lists each board.

TP00000002.connect()
Needs: import wireless · Firmware: 2.24+

Starts the link to that board (in setup:). The ID is the other board's Device ID (Menu > Device info). The link opens when BOTH boards' programs list each other, and comes back by itself if a board was off.

Example 1 — Links to board TP00000002 and says hi every second.
setup:
    TP00000002.connect()
loop:
    TP00000002.send("hi")
    wait(1000)
Example 2 — One board can link to up to 6 boards.
setup:
    TP00000002.connect()
    TP00000003.connect()
loop:
    wireless_send_all("ping")
    wait(2000)
Example 3 — o1 shows when the link is up.
setup:
    TP00000002.connect()
loop:
    if TP00000002.connected() == 1:
        o1 = ON
    else:
        o1 = OFF
TP00000002.send(value)
Needs: import wireless · Firmware: 2.24+

Sends text, a number or a join ("T" + temp) to that board — up to 30 characters. Gives 1 when the board got it, 0 when not (not linked or out of range); use it on its own line when you do not need to check.

value"text", a number, a variable or a join like "T" + temp.
Example 1 — A button on this board switches a light on the other one.
setup:
    TP00000002.connect()
loop:
    if i1 == ON:
        TP00000002.send("ON")
    else:
        TP00000002.send("OFF")
    wait(200)
Example 2 — Sends a number (a reading) every second.
setup:
    TP00000002.connect()
loop:
    t = 25
    TP00000002.send(t)
    wait(1000)
Example 3 — o3 lights when the message did not arrive.
setup:
    TP00000002.connect()
loop:
    ok = TP00000002.send("ALARM")
    if ok == 0:
        o3 = ON
    wait(500)
TP00000002.available()
Needs: import wireless · Firmware: 2.24+

1 when a message from that board arrived (it is there for one loop), 0 when not.

Example 1 — Blinks o1 for every message.
setup:
    TP00000002.connect()
loop:
    if TP00000002.available() == 1:
        o1 = ON
        wait(200)
        o1 = OFF
Example 2 — Passes each message on to the phone app.
setup:
    TP00000002.connect()
    bluetooth_begin()
loop:
    if TP00000002.available() == 1:
        msg = TP00000002.read()
        bluetooth_write(msg)
Example 3 — o2 off while nothing comes.
setup:
    TP00000002.connect()
loop:
    if TP00000002.available() == 0:
        o2 = OFF
TP00000002.read()
Needs: import wireless · Firmware: 2.24+

The message from that board as text (None when nothing came). Store it (msg = TP00000002.read()), compare it or show it.

Example 1 — The other board switches o1 on and off.
setup:
    TP00000002.connect()
loop:
    msg = TP00000002.read()
    if msg == "ON":
        o1 = ON
    elif msg == "OFF":
        o1 = OFF
Example 2 — Shows each message on the OLED.
setup:
    TP00000002.connect()
    oled_begin()
loop:
    msg = TP00000002.read()
    if msg != None:
        oled_write(1, left, small, regular, "Got: " + msg)
Example 3 — A buzzer beeps when the friend sends BUZZ.
setup:
    TP00000002.connect()
loop:
    if TP00000002.read() == "BUZZ":
        o1 = ON
        wait(300)
        o1 = OFF
TP00000002.read_number()
Needs: import wireless · Firmware: 2.24+

The message from that board as a number (a sensor reading) — None when nothing came or it is not a number.

Example 1 — Lights o1 when the other board's distance is under 20.
setup:
    TP00000002.connect()
loop:
    d = TP00000002.read_number()
    if d != None and d < 20:
        o1 = ON
Example 2 — Turns a servo to the angle the other board sends.
setup:
    TP00000002.connect()
loop:
    a = TP00000002.read_number()
    if a != None:
        o2 = servo_angle(a)
Example 3 — Shows the temperature sent by the other board.
setup:
    TP00000002.connect()
    oled_begin()
loop:
    t = TP00000002.read_number()
    if t != None:
        oled_write(1, center, large, bold, t)
TP00000002.signal()
Needs: import wireless · Firmware: 2.24+

How strong that board's signal is: 0–100 (0 = not heard). A "how close is my friend" sensor.

Example 1 — An out-of-range alarm.
setup:
    TP00000002.connect()
loop:
    if TP00000002.signal() < 20:
        o1 = ON
    else:
        o1 = OFF
Example 2 — The LED gets brighter as the friend comes closer.
setup:
    TP00000002.connect()
loop:
    s = TP00000002.signal()
    o1 = pwm(s)
Example 3 — Shows the signal on the OLED.
setup:
    TP00000002.connect()
    oled_begin()
loop:
    oled_write(1, left, small, regular, "Signal " + TP00000002.signal())
    wait(500)
TP00000002.connected()
Needs: import wireless · Firmware: 2.24+

1 while the link to that board is up (both boards list each other and hear each other), 0 when not.

Example 1 — o1 shows the link.
setup:
    TP00000002.connect()
loop:
    if TP00000002.connected() == 1:
        o1 = ON
    else:
        o1 = OFF
Example 2 — o2 blinks while waiting for the friend.
setup:
    TP00000002.connect()
loop:
    if TP00000002.connected() == 0:
        o2 = ON
        wait(200)
        o2 = OFF
        wait(200)
Example 3 — Sends only while linked.
setup:
    TP00000002.connect()
loop:
    if TP00000002.connected() == 1 and i1 == ON:
        TP00000002.send("GO")
TP00000002.disconnect()
Needs: import wireless · Firmware: 2.24+

Closes the link to that board and stops taking its messages (connect() opens it again).

Example 1 — Buttons to stop and start the link.
setup:
    TP00000002.connect()
loop:
    if i1 == ON:
        TP00000002.disconnect()
    if i2 == ON:
        TP00000002.connect()
Example 2 — Stops listening when the friend says BYE.
setup:
    TP00000002.connect()
loop:
    if TP00000002.read() == "BYE":
        TP00000002.disconnect()
Example 3 — Closes the link when the friend is too far.
setup:
    TP00000002.connect()
loop:
    if TP00000002.signal() < 5:
        TP00000002.disconnect()
wireless_send_all(value)
Needs: import wireless · Firmware: 2.24+

Sends to every linked board at once; gives how many got it.

value"text", a number, a variable or a join.
Example 1 — One button stops all robots.
setup:
    TP00000002.connect()
    TP00000003.connect()
loop:
    if i1 == ON:
        wireless_send_all("STOP")
Example 2 — o1 lights when not every board got it.
setup:
    TP00000002.connect()
    TP00000003.connect()
loop:
    n = wireless_send_all("hi")
    if n < 2:
        o1 = ON
    wait(1000)
Example 3 — Sends a reading to all boards.
setup:
    TP00000002.connect()
    TP00000003.connect()
loop:
    t = 30
    wireless_send_all("T" + t)
    wait(2000)
id, data = wireless_read_any()
Needs: import wireless · Firmware: 2.24+

The next message from ANY linked board: id = who sent it ("TP00000003"), data = the message. Both None when nothing came.

Example 1 — Listens to two boards at once.
setup:
    TP00000002.connect()
    TP00000003.connect()
loop:
    id, data = wireless_read_any()
    if id == "TP00000003":
        o1 = ON
    if data == "OFF":
        o1 = OFF
Example 2 — A hub that shows who sent what.
setup:
    TP00000002.connect()
    TP00000003.connect()
    oled_begin()
loop:
    id, data = wireless_read_any()
    if id != None:
        oled_write(1, left, small, regular, id + ": " + data)
Example 3 — Passes every board's messages to the phone.
setup:
    TP00000002.connect()
    TP00000003.connect()
    bluetooth_begin()
loop:
    id, data = wireless_read_any()
    if data != None:
        bluetooth_write(data)

Wireless IoT Function

Board to board over the internet (firmware 2.25, TinkerPy Mega). The same functions as Wireless with _iot after the ID: TP00000002_iot.send("ON"). The boards can be anywhere — each on its own WiFi; tinkerpy.com passes the messages, so a message takes a few seconds (about 5–10 s free, 2–4 s Pro; the board checks in every 5 s / 2 s while the program uses wireless_iot). A link opens only when both boards’ programs list each other. send() gives 1 when the message is on its way (the other board is online and linked). No signal() — use connected(). A program uses wireless (radio) or wireless_iot, not both; iot_ and bluetooth_ functions work with either. Up to 6 boards, 30 characters per message; a message waits up to 60 s. Menu → Wireless devices shows them (“OK net”).

TP00000002_iot.connect()
Needs: import wireless_iot · Firmware: 2.25+

Starts the link to that board over the internet (in setup:). The ID is the other board's Device ID (Menu > Device info) with _iot after it. Both boards must be online (WiFi); the link opens when BOTH boards' programs list each other.

Example 1 — Links to board TP00000002 over the internet and says hi every 5 seconds.
setup:
    TP00000002_iot.connect()
loop:
    TP00000002_iot.send("hi")
    wait(5000)
Example 2 — One board can link to up to 6 boards.
setup:
    TP00000002_iot.connect()
    TP00000003_iot.connect()
loop:
    wireless_iot_send_all("ping")
    wait(2000)
Example 3 — o1 shows when the link is up.
setup:
    TP00000002_iot.connect()
loop:
    if TP00000002_iot.connected() == 1:
        o1 = ON
    else:
        o1 = OFF
TP00000002_iot.send(value)
Needs: import wireless_iot · Firmware: 2.25+

Sends text, a number or a join ("T" + temp) to that board through tinkerpy.com — up to 30 characters; it arrives in a few seconds (about 5–10 s free, 2–4 s Pro). Gives 1 when it is on its way (that board is online and linked), 0 when not.

value"text", a number, a variable or a join like "T" + temp.
Example 1 — A button on this board switches a light on the other one.
setup:
    TP00000002_iot.connect()
loop:
    if i1 == ON:
        TP00000002_iot.send("ON")
    else:
        TP00000002_iot.send("OFF")
    wait(200)
Example 2 — Sends a number (a reading) every second.
setup:
    TP00000002_iot.connect()
loop:
    t = 25
    TP00000002_iot.send(t)
    wait(1000)
Example 3 — o3 lights when the other board is not online.
setup:
    TP00000002_iot.connect()
loop:
    ok = TP00000002_iot.send("ALARM")
    if ok == 0:
        o3 = ON
    wait(500)
TP00000002_iot.available()
Needs: import wireless_iot · Firmware: 2.25+

1 when a message from that board arrived (it is there for one loop), 0 when not.

Example 1 — Blinks o1 for every message.
setup:
    TP00000002_iot.connect()
loop:
    if TP00000002_iot.available() == 1:
        o1 = ON
        wait(200)
        o1 = OFF
Example 2 — Passes each message on to the phone app.
setup:
    TP00000002_iot.connect()
    bluetooth_begin()
loop:
    if TP00000002_iot.available() == 1:
        msg = TP00000002_iot.read()
        bluetooth_write(msg)
Example 3 — o2 off while nothing comes.
setup:
    TP00000002_iot.connect()
loop:
    if TP00000002_iot.available() == 0:
        o2 = OFF
TP00000002_iot.read()
Needs: import wireless_iot · Firmware: 2.25+

The message from that board as text (None when nothing came). Store it (msg = TP00000002_iot.read()), compare it or show it.

Example 1 — The other board switches o1 on and off.
setup:
    TP00000002_iot.connect()
loop:
    msg = TP00000002_iot.read()
    if msg == "ON":
        o1 = ON
    elif msg == "OFF":
        o1 = OFF
Example 2 — Shows each message on the OLED.
setup:
    TP00000002_iot.connect()
    oled_begin()
loop:
    msg = TP00000002_iot.read()
    if msg != None:
        oled_write(1, left, small, regular, "Got: " + msg)
Example 3 — A buzzer beeps when the friend sends BUZZ.
setup:
    TP00000002_iot.connect()
loop:
    if TP00000002_iot.read() == "BUZZ":
        o1 = ON
        wait(300)
        o1 = OFF
TP00000002_iot.read_number()
Needs: import wireless_iot · Firmware: 2.25+

The message from that board as a number (a sensor reading) — None when nothing came or it is not a number.

Example 1 — Lights o1 when the other board's distance is under 20.
setup:
    TP00000002_iot.connect()
loop:
    d = TP00000002_iot.read_number()
    if d != None and d < 20:
        o1 = ON
Example 2 — Turns a servo to the angle the other board sends.
setup:
    TP00000002_iot.connect()
loop:
    a = TP00000002_iot.read_number()
    if a != None:
        o2 = servo_angle(a)
Example 3 — Shows the temperature sent by the other board.
setup:
    TP00000002_iot.connect()
    oled_begin()
loop:
    t = TP00000002_iot.read_number()
    if t != None:
        oled_write(1, center, large, bold, t)
TP00000002_iot.connected()
Needs: import wireless_iot · Firmware: 2.25+

1 while that board is online and linked (both programs list each other), 0 when not.

Example 1 — o1 shows the link.
setup:
    TP00000002_iot.connect()
loop:
    if TP00000002_iot.connected() == 1:
        o1 = ON
    else:
        o1 = OFF
Example 2 — o2 blinks while the friend is offline.
setup:
    TP00000002_iot.connect()
loop:
    if TP00000002_iot.connected() == 0:
        o2 = ON
        wait(200)
        o2 = OFF
        wait(200)
Example 3 — Sends only while linked.
setup:
    TP00000002_iot.connect()
loop:
    if TP00000002_iot.connected() == 1 and i1 == ON:
        TP00000002_iot.send("GO")
TP00000002_iot.disconnect()
Needs: import wireless_iot · Firmware: 2.25+

Closes the link to that board and stops taking its messages (connect() opens it again).

Example 1 — Buttons to stop and start the link.
setup:
    TP00000002_iot.connect()
loop:
    if i1 == ON:
        TP00000002_iot.disconnect()
    if i2 == ON:
        TP00000002_iot.connect()
Example 2 — Stops listening when the friend says BYE.
setup:
    TP00000002_iot.connect()
loop:
    if TP00000002_iot.read() == "BYE":
        TP00000002_iot.disconnect()
Example 3 — Stops the link when the friend says STOP.
setup:
    TP00000002_iot.connect()
loop:
    if TP00000002_iot.read() == "STOP":
        TP00000002_iot.disconnect()
        o1 = OFF
wireless_iot_send_all(value)
Needs: import wireless_iot · Firmware: 2.25+

Sends to every linked board at once over the internet; gives how many it is on its way to.

value"text", a number, a variable or a join.
Example 1 — One button stops all robots.
setup:
    TP00000002_iot.connect()
    TP00000003_iot.connect()
loop:
    if i1 == ON:
        wireless_iot_send_all("STOP")
Example 2 — o1 lights when not every board got it.
setup:
    TP00000002_iot.connect()
    TP00000003_iot.connect()
loop:
    n = wireless_iot_send_all("hi")
    if n < 2:
        o1 = ON
    wait(1000)
Example 3 — Sends a reading to all boards.
setup:
    TP00000002_iot.connect()
    TP00000003_iot.connect()
loop:
    t = 30
    wireless_iot_send_all("T" + t)
    wait(2000)
id, data = wireless_iot_read_any()
Needs: import wireless_iot · Firmware: 2.25+

The next message from ANY linked board: id = who sent it ("TP00000003"), data = the message. Both None when nothing came.

Example 1 — Listens to two boards at once.
setup:
    TP00000002_iot.connect()
    TP00000003_iot.connect()
loop:
    id, data = wireless_iot_read_any()
    if id == "TP00000003":
        o1 = ON
    if data == "OFF":
        o1 = OFF
Example 2 — A hub that shows who sent what.
setup:
    TP00000002_iot.connect()
    TP00000003_iot.connect()
    oled_begin()
loop:
    id, data = wireless_iot_read_any()
    if id != None:
        oled_write(1, left, small, regular, id + ": " + data)
Example 3 — Passes every board's messages to the phone.
setup:
    TP00000002_iot.connect()
    TP00000003_iot.connect()
    bluetooth_begin()
loop:
    id, data = wireless_iot_read_any()
    if data != None:
        bluetooth_write(data)

Joystick Function

joystick_x()
Needs: import joystick · Firmware: 2.18+

How far the stick is pushed left or right: −100 (left) to 100 (right), 0 in the middle. The X wire goes on i1–i4.

Example 1 — The stick turns a servo left and right.
setup:
    i1 = set_function(joystick_x)
o1 = servo_angle(90 + joystick_x() * 9 / 10)
Example 2 — A light comes on when the stick is pushed right.
x = joystick_x()
if x > 50:
    o1 = ON
else:
    o1 = OFF
Example 3 — Shows the X value on the OLED.
oled_write(1, left, small, regular, joystick_x())
joystick_y()
Needs: import joystick · Firmware: 2.18+

How far the stick is pushed up or down: −100 (down) to 100 (up), 0 in the middle. The Y wire goes on i1–i4.

Example 1 — Push up to make the light brighter.
y = joystick_y()
if y > 0:
    o1 = pwm(y)
else:
    o1 = OFF
Example 2 — Sends the Y value to the app.
setup:
    i2 = set_function(joystick_y)
bluetooth_write(joystick_y())
Example 3 — A level meter that follows the stick.
rgb_bar(o3, all, "rainbow", joystick_y(), 100)
joystick_direction()
Needs: import joystick · Firmware: 2.18+

Where the stick points: 'F' (up), 'B' (down), 'L', 'R' — or 'S' in the middle. Like the app's Digital Joystick.

Example 1 — Drives a robot with the joystick.
d = joystick_direction()
if d == 'F':
    robot_control("F", 80, "F", 80)
elif d == 'B':
    robot_control("B", 80, "B", 80)
elif d == 'S':
    robot_control("S", 0, "S", 0)
Example 2 — A light for pushing left.
if joystick_direction() == 'L':
    o1 = ON
Example 3 — Sends F / B / L / R / S to the app.
bluetooth_write(joystick_direction())
joystick_pressed()
Needs: import joystick · Firmware: 2.18+

1 while the stick is pushed in (its switch), otherwise 0. The SW wire can go on any pin.

Example 1 — A buzzer while the stick is pushed in.
if joystick_pressed() == 1:
    o2 = ON
else:
    o2 = OFF
Example 2 — The switch on o5 flips an RGB LED.
setup:
    o5 = set_function(joystick_swt)
if joystick_pressed() == 1:
    rgb_flip(o1, 1, "green")
Example 3 — Counts the presses.
if joystick_pressed() == 1:
    c1.increment()
    wait(300)

RGB LED Function

rgb_begin(output, number_of_leds)
Needs: import rgb_single or import rgb_two or import rgb_three or import rgb_strip · Firmware: 2.17+

Goes inside setup: — says which output the RGB LEDs are on and how many there are. Added for you when you tick an RGB LED library.

outputThe output the LED board or strip is plugged into, like o1.
number_of_leds1, 2 or 3 for an LED board, or how many LEDs your strip has (max 60).
Example 1 — A single-LED board on o1.
setup:
    rgb_begin(o1, 1)
Example 2 — A 3-LED board on o1.
setup:
    rgb_begin(o1, 3)
Example 3 — A strip with 30 LEDs on o2.
setup:
    rgb_begin(o2, 30)
Example 4 — Two boards at once: 2 LEDs on o1 and a 60-LED strip on o2 (up to 4 boards).
setup:
    rgb_begin(o1, 2)
    rgb_begin(o2, 60)
rgb_color(output, led, "color", brightness)
Needs: import rgb_single or import rgb_two or import rgb_three or import rgb_strip · Firmware: 2.17+

Lights an LED (or all of them) in a colour. Brightness can be left out (100).

outputThe output with the RGB LEDs, like o1.
ledWhich LED: 1, 2, 3 … or all.
colorred, green, blue, yellow, orange, purple, pink, cyan, white, warm_white, off, random, rainbow — or a code like "#FF8800".
brightnessOptional, 0–100. Left out = 100.
Example 1 — Every LED turns red.
rgb_color(o1, all, "red")
Example 2 — LED 2 turns orange at 40% brightness.
rgb_color(o1, 2, "#FF8800", 40)
Example 3 — Green while the button is pressed.
if i1 == ON:
    rgb_color(o1, all, "green")
else:
    rgb_color(o1, all, "off")
Example 4 — Spreads the rainbow over all the LEDs.
rgb_color(o1, all, "rainbow")
rgb_flip(output, led, "color", brightness)
Needs: import rgb_single or import rgb_two or import rgb_three or import rgb_strip · Firmware: 2.17+

Each new press flips the LED: on in that colour, then off, then on… While the button stays pressed nothing changes. Brightness can be left out (100).

outputThe output with the RGB LEDs, like o1.
ledWhich LED: 1, 2, 3 … or all.
colorThe colour it turns on in — a name, "#FF8800", random or rainbow.
brightnessOptional, 0–100. Left out = 100.
Example 1 — Press once: LED 1 turns red. Press again: off.
if i1 == ON:
    rgb_flip(o1, 1, "red")
Example 2 — A press on/off lamp for the whole strip.
if i2 == ON:
    rgb_flip(o1, all, "white")
Example 3 — Two buttons, each one flips its own LED.
if i1 == ON:
    rgb_flip(o1, 1, "green")
if i2 == ON:
    rgb_flip(o1, 2, "blue")
rgb_hex_color(output, led, r, g, b)
Needs: import rgb_single or import rgb_two or import rgb_three or import rgb_strip · Firmware: 2.17+

Mixes any colour from red, green and blue (0–255 each, like a colour picker). Numbers or variables.

outputThe output with the RGB LEDs, like o1.
ledWhich LED: 1, 2, 3 … or all.
rHow much red, 0–255.
gHow much green, 0–255.
bHow much blue, 0–255.
Example 1 — Mixes orange (lots of red, some green).
rgb_hex_color(o1, all, 255, 120, 0)
Example 2 — LED 1 gets bluer as the reading goes up.
light = analog_read(i1)
rgb_hex_color(o1, 1, 0, 0, light * 2)
Example 3 — A random mix between red and blue.
red = random(0, 255)
rgb_hex_color(o1, all, red, 0, 255 - red)
rgb_blink(output, led, "color", on_ms, off_ms)
Needs: import rgb_single or import rgb_two or import rgb_three or import rgb_strip · Firmware: 2.17+

Blinks by itself while your code keeps running. on_ms and off_ms can be left out (500).

outputThe output with the RGB LEDs, like o1.
ledWhich LED: 1, 2, 3 … or all.
colorA colour name, "#FF8800", random or rainbow (a new colour each blink).
on_msOptional: how long it is on, in ms (500).
off_msOptional: how long it is off (same as on_ms).
Example 1 — LED 1 blinks red, half a second on, half off.
rgb_blink(o1, 1, "red")
Example 2 — All LEDs blink fast in a new colour each time.
rgb_blink(o1, all, "random", 300)
Example 3 — A short flash every second, like a beacon.
rgb_blink(o1, 2, "white", 100, 900)
rgb_breathe(output, led, "color", time_ms)
Needs: import rgb_single or import rgb_two or import rgb_three or import rgb_strip · Firmware: 2.17+

Slowly fades in and out, by itself. time_ms can be left out (2000).

outputThe output with the RGB LEDs, like o1.
ledWhich LED: 1, 2, 3 … or all.
colorA colour name, "#FF8800", random or rainbow.
time_msOptional: one breath, in ms (2000).
Example 1 — A calm purple glow.
rgb_breathe(o1, all, "purple")
Example 2 — Each breath in the next rainbow colour.
rgb_breathe(o1, 1, "rainbow", 3000)
Example 3 — Breathes while waiting; green when pressed.
if i1 == OFF:
    rgb_breathe(o1, all, "blue")
else:
    rgb_color(o1, all, "green")
rgb_swap(output, led, "color", "color2", time_ms)
Needs: import rgb_single or import rgb_two or import rgb_three or import rgb_strip · Firmware: 2.17+

Swaps between two colours, by itself — neighbouring LEDs take turns, like police lights.

outputThe output with the RGB LEDs, like o1.
ledWhich LED: 1, 2, 3 … or all.
colorThe first colour.
color2Optional: the second colour ("off").
time_msOptional: how long each colour stays, in ms (500).
Example 1 — Police lights.
rgb_swap(o1, all, "red", "blue", 300)
Example 2 — LED 1 flashes yellow on and off.
rgb_swap(o1, 1, "yellow")
Example 3 — A slow festive swap.
rgb_swap(o1, all, "green", "white", 1000)
rgb_chase(output, led, "color", speed_ms)
Needs: import rgb_single or import rgb_two or import rgb_three or import rgb_strip · Firmware: 2.17+

One light runs along the LEDs, by itself. With a number it runs over LEDs 1 to that number. "rainbow" makes a moving rainbow.

outputThe output with the RGB LEDs, like o1.
ledall (the whole strip) or a number n (LEDs 1 to n).
colorA colour name, "#FF8800", random or rainbow.
speed_msOptional: time per step, in ms (100).
Example 1 — A blue light runs along the strip.
rgb_chase(o1, all, "blue")
Example 2 — A moving rainbow.
rgb_chase(o1, all, "rainbow", 50)
Example 3 — Runs over LEDs 1–3 only.
rgb_chase(o1, 3, "red", 200)
rgb_wipe(output, led, "color", speed_ms)
Needs: import rgb_single or import rgb_two or import rgb_three or import rgb_strip · Firmware: 2.17+

Fills the LEDs one after another, then stays on. With a number it fills LEDs 1 to that number.

outputThe output with the RGB LEDs, like o1.
ledall or a number n (LEDs 1 to n).
colorA colour name, "#FF8800", random or rainbow.
speed_msOptional: time per LED, in ms (50).
Example 1 — The strip fills up with green.
rgb_wipe(o1, all, "green")
Example 2 — Fills with a rainbow.
rgb_wipe(o1, all, "rainbow", 30)
Example 3 — A quick white fill when the button is pressed.
if i1 == ON:
    rgb_wipe(o1, all, "white", 20)
rgb_twinkle(output, led, "color", speed_ms)
Needs: import rgb_single or import rgb_two or import rgb_three or import rgb_strip · Firmware: 2.17+

LEDs sparkle at random, like stars, by themselves.

outputThe output with the RGB LEDs, like o1.
ledall or a number n (LEDs 1 to n).
colorA colour name, "#FF8800", random or rainbow.
speed_msOptional: how fast, in ms (100).
Example 1 — Starry sky.
rgb_twinkle(o1, all, "white")
Example 2 — Party sparkles in every colour.
rgb_twinkle(o1, all, "random", 60)
Example 3 — Gentle fairy lights.
rgb_twinkle(o1, all, "warm_white", 200)
rgb_bar(output, led, "color", value, max)
Needs: import rgb_single or import rgb_two or import rgb_three or import rgb_strip · Firmware: 2.17+

A level meter: lights more LEDs as the value goes up. "rainbow" goes green → yellow → red.

outputThe output with the RGB LEDs, like o1.
ledall or a number n (use LEDs 1 to n).
colorA colour name, "#FF8800" or rainbow (green to red).
valueThe level to show — a number or a reading.
maxOptional: the value that lights every LED (100).
Example 1 — A soil / light meter from 0 to 100.
rgb_bar(o1, all, "green", analog_read(i1))
Example 2 — Fills up as something comes closer.
d = distance()
rgb_bar(o1, all, "rainbow", 100 - d, 100)
Example 3 — Shows a counter from 0 to 10.
rgb_bar(o1, all, "blue", c1, 10)
rgb_heat(output, led, "color", value, low, high)
Needs: import rgb_single or import rgb_two or import rgb_three or import rgb_strip · Firmware: 2.17+

The colour follows a value: blue at low, the colour you pick at high. "rainbow" goes blue → green → red.

outputThe output with the RGB LEDs, like o1.
ledWhich LED: 1, 2, 3 … or all.
colorThe colour at high (like red), or rainbow.
valueThe number to show — a reading or a variable.
lowOptional: blue at this value (0).
highOptional: full colour at this value (100).
Example 1 — A thermometer light: blue when cool, red when hot.
rgb_heat(o1, all, "red", dht_temperature(i1), 20, 40)
Example 2 — A dial from blue to red.
rgb_heat(o1, 1, "rainbow", analog_read(i1))
Example 3 — Turns from blue to green as the counter climbs.
rgb_heat(o1, all, "green", c1, 0, 20)

LCD Display Function

lcd_begin(address)
Needs: import lcd_16x2 · Firmware: 2.16+

Starts the LCD. Goes inside setup: — added for you when you tick the 16x2 LCD.

addressThe LCD’s I2C address — most are 0x27 or 0x3F. Leave it empty, lcd_begin(), and the board finds it.
Example 1 — The most common LCD address.
setup:
    lcd_begin(0x27)
Example 2 — Some LCD modules use 0x3F instead.
setup:
    lcd_begin(0x3F)
Example 3 — Not sure? The board looks for the LCD by itself.
setup:
    lcd_begin()
lcd_write(line, position, value)
Needs: import lcd_16x2 · Firmware: 2.16+

Writes text or a number on the LCD, starting at a place on a line.

lineWhich line: 1 or 2.
positionWhere on the line to start: 1 (left) to 16 (right).
valueText in quotes, or a number / variable.
Example 1 — Writes on line 1, from the left.
lcd_write(1, 1, "Hello!")
Example 2 — A label and a live number on the same line.
lcd_write(2, 1, "Temp:")
lcd_write(2, 7, dht_temperature(i1))
Example 3 — Starts at place 6 — good for centring short words.
lcd_write(1, 6, "Hi")
lcd_clear()
Needs: import lcd_16x2 · Firmware: 2.16+

Clears the whole LCD.

Example 1 — Wipes both lines blank.
lcd_clear()
Example 2 — Shows a message for 2 seconds, then clears it.
lcd_write(1, 1, "Hello")
wait(2000)
lcd_clear()
Example 3 — Clears the screen when a button is pressed.
if i1 == ON:
    lcd_clear()
lcd_clear_line(line)
Needs: import lcd_16x2 · Firmware: 2.16+

Clears just one line of the LCD.

lineWhich line to clear: 1 or 2.
Example 1 — Clears line 2, line 1 stays.
lcd_clear_line(2)
Example 2 — Clear first, so an old longer number never leaves digits behind.
count = 5
lcd_clear_line(1)
lcd_write(1, 1, count)
Example 3 — Removes a message when the button is let go.
if i1 == OFF:
    lcd_clear_line(2)
lcd_scroll(line, text)
Needs: import lcd_16x2 · Firmware: 2.16+

Scrolls long text along a line. It keeps scrolling by itself while the rest of your code runs.

lineWhich line: 1 or 2.
textThe text to scroll, in quotes.
Example 1 — A moving welcome message on line 1.
lcd_scroll(1, "Welcome to TinkerPy!")
Example 2 — Line 1 scrolls while line 2 shows a reading.
lcd_scroll(1, "Smart Plant Monitor")
lcd_write(2, 1, analog_read(i1))
Example 3 — Clearing the line stops the scrolling.
lcd_scroll(2, "News: it is hot today")
wait(5000)
lcd_clear_line(2)
lcd_backlight(ON / OFF)
Needs: import lcd_16x2 · Firmware: 2.16+

Switches the LCD’s backlight on or off. The text stays.

ON / OFFON lights the screen, OFF darkens it.
Example 1 — Darkens the screen to save power.
lcd_backlight(OFF)
Example 2 — Lights the screen only while the button is pressed.
if i1 == ON:
    lcd_backlight(ON)
else:
    lcd_backlight(OFF)
Example 3 — Blinks the screen once to get attention.
lcd_backlight(OFF)
wait(500)
lcd_backlight(ON)

OLED Display Function

oled_begin(address)
Needs: import oled_display · Firmware: 2.16+

Starts the OLED. Goes inside setup: — added for you when you tick the OLED.

addressOptional. Most OLEDs are 0x3C (used when empty); a few are 0x3D.
Example 1 — Starts the OLED at its usual address.
setup:
    oled_begin()
Example 2 — For an OLED set to address 0x3D.
setup:
    oled_begin(0x3D)
Example 3 — An OLED and an LCD together — each shows what its own functions write.
setup:
    oled_begin()
    lcd_begin(0x27)
oled_write(line, align, size, weight, value)
Needs: import oled_display · Firmware: 2.20+

Writes text or a number on a line of the OLED (it replaces that line). The OLED has 4 lines. Sizes: small = 21 letters, 1 line · medium = 10 letters, 2 lines · large = 7 letters, 2 lines (medium and large also use the line below, so start them on line 1, 2 or 3).

lineWhich line: 1 to 4 (medium / large: 1 to 3 — they take 2 lines).
alignleft, center or right.
sizesmall (21 letters, 1 line), medium (10 letters, 2 lines) or large (7 letters, 2 lines).
weightregular or bold.
valueText in quotes, or a number / variable.
Example 1 — Small text on line 3, from the left.
oled_write(3, left, small, regular, "Sensor ON")
Example 2 — A big bold number in the middle of lines 1–2.
oled_write(1, center, large, bold, c1)
Example 3 — A title, a label and a live value on the right.
oled_write(1, center, medium, bold, "Weather")
oled_write(3, left, small, regular, "Temp")
oled_write(4, right, small, regular, dht_temperature(i1))
oled_clear()
Needs: import oled_display · Firmware: 2.16+

Clears the whole OLED.

Example 1 — Wipes the screen blank.
oled_clear()
Example 2 — Shows a message for 2 seconds, then clears it.
oled_write(1, left, small, regular, "Hello")
wait(2000)
oled_clear()
Example 3 — Clears the screen when a button is pressed.
if i1 == ON:
    oled_clear()
oled_clear_line(line)
Needs: import oled_display · Firmware: 2.16+

Clears just one line of the OLED.

lineWhich line to clear: 1 to 4.
Example 1 — Clears line 3, the others stay.
oled_clear_line(3)
Example 2 — Removes a message when the button is let go.
if i1 == OFF:
    oled_clear_line(4)
Example 3 — Shows a message for a second, then removes it.
oled_write(2, left, small, regular, "Saved!")
wait(1000)
oled_clear_line(2)
oled_eye_animation(name, repeat, speed, delay)
Needs: import oled_display · Firmware: 2.19+

Robot eyes on the whole OLED: blink, look_left, look_right, look_up, look_down, look_around, happy, sad, angry, sleepy, surprised, wink, love, dizzy, suspicious, crying, confused, wake_up. It plays by itself while the rest of your code runs; oled_write / oled_clear stop it. Try them all on the board: Menu > Animations > Eyes.

nameWhich animation, in quotes, e.g. "blink".
repeatHow many times it plays. 0 = for ever.
speed1 (slow) to 10 (fast). 5 is normal.
delayPause between repeats in milliseconds (1000 = 1 second).
Example 1 — A robot face that blinks every 2 seconds, for ever.
oled_eye_animation("blink", 0, 5, 2000)
Example 2 — Happy eyes when the button is pressed, looking around otherwise.
if i1 == ON:
    oled_eye_animation("happy", 2, 6, 300)
else:
    oled_eye_animation("look_around", 0, 4, 1000)
Example 3 — Falls asleep, then text takes the screen back.
oled_eye_animation("sleepy", 1, 3, 0)
wait(4000)
oled_write(1, left, small, regular, "Good night")
oled_emoji_animation(name, repeat, speed, delay)
Needs: import oled_display · Firmware: 2.19+

A moving emoji on the whole OLED: smile, laugh, wink, love, sad, cry, angry, surprised, sleepy, cool, tongue, heart, star, thinking, kiss. Plays by itself; oled_write / oled_clear stop it. See them all: Menu > Animations > Emoji.

nameWhich emoji, in quotes, e.g. "smile".
repeatHow many times it plays. 0 = for ever.
speed1 (slow) to 10 (fast). 5 is normal.
delayPause between repeats in milliseconds.
Example 1 — A heart that keeps beating.
oled_emoji_animation("heart", 0, 6, 0)
Example 2 — Laughs when tickled (button), sleeps otherwise.
if i1 == ON:
    oled_emoji_animation("laugh", 3, 7, 0)
else:
    oled_emoji_animation("sleepy", 0, 3, 500)
Example 3 — Sunglasses slide down — once.
oled_emoji_animation("cool", 1, 5, 0)
oled_scroll(line, text)
Needs: import oled_display · Firmware: 2.16+

Scrolls long text along a line. It keeps scrolling by itself while the rest of your code runs.

lineWhich line: 1 to 4.
textThe text to scroll, in quotes.
Example 1 — A moving welcome message on line 1.
oled_scroll(1, "Welcome to TinkerPy!")
Example 2 — Line 4 scrolls while line 1 stays still.
oled_scroll(4, "Press the button to start")
oled_write(1, left, small, regular, "Game")
Example 3 — Clearing the line stops the scrolling.
oled_scroll(2, "Game over")
wait(5000)
oled_clear_line(2)

Counter Function

c1.auto_increment(interval_ms)
Needs: import counter

Starts counting up by 1, automatically, forever, in the background — once every interval_ms.

interval_msHow often to add 1, in milliseconds (1–32767). 1000 = once a second.
Example 1 — Counts up once a second, shown live on the display.
setup:
    c1.auto_increment(1000)
loop:
    oled_write(1, left, small, regular, c1)
Example 2 — Counts up fast; turns o1 on once it passes 50.
setup:
    c1.auto_increment(200)
loop:
    if c1 > 50:
        o1 = pwm(100)
Example 3 — Two counters can tick at completely different speeds at once.
setup:
    c1.auto_increment(1000)
    c2.auto_increment(500)
c1.auto_decrement(interval_ms)
Needs: import counter

Starts counting down by 1, automatically, forever, in the background — once every interval_ms.

interval_msHow often to subtract 1, in milliseconds (1–32767).
Example 1 — A 60-second countdown, shown live on the display.
setup:
    c1.set(60)
    c1.auto_decrement(1000)
loop:
    oled_write(1, left, small, regular, c1)
Example 2 — Counts down from 10, then turns o1 on when it hits 0.
setup:
    c1.set(10)
    c1.auto_decrement(500)
loop:
    if c1 == 0:
        o1 = pwm(100)
Example 3 — A fast countdown, subtracting 1 every 100ms.
setup:
    c1.set(100)
    c1.auto_decrement(100)
c1.increment()
Needs: import counter

Adds 1 to the counter, once, right now — not automatic.

Example 1 — Counts how many times the button has been pressed.
if i1 == ON:
    c1.increment()
Example 2 — Adds 1 and shows the new total.
c1.increment()
oled_write(1, left, small, regular, c1)
Example 3 — Adds 1 five times in a row — c1 ends up at 5.
repeat(5):
    c1.increment()
c1.decrement()
Needs: import counter

Subtracts 1 from the counter, once, right now — not automatic.

Example 1 — A second button counts back down.
if i2 == ON:
    c1.decrement()
Example 2 — Starts at 10, subtracts 1, shows 9.
setup:
    c1.set(10)
loop:
    c1.decrement()
    oled_write(1, left, small, regular, c1)
Example 3 — One button counts up, another counts down.
if i1 == ON:
    c1.increment()
if i2 == ON:
    c1.decrement()
c1.clear()
Needs: import counter

Resets the counter to 0. Doesn’t stop auto_increment/auto_decrement if either is running.

Example 1 — A button resets the counter back to 0.
if i1 == ON:
    c1.clear()
Example 2 — Counts up, then resets itself once it passes 10.
c1.increment()
if c1 > 10:
    c1.clear()
Example 3 — Keeps auto-counting, but a button can reset it back to 0 at any time.
setup:
    c1.auto_increment(1000)
loop:
    if i1 == ON:
        c1.clear()
c1.pause()
Needs: import counter

Stops auto_increment/auto_decrement, freezing the counter where it is.

Example 1 — Counts up automatically until a button freezes it.
setup:
    c1.auto_increment(1000)
loop:
    if i1 == ON:
        c1.pause()
Example 2 — A countdown that stops itself at 0, instead of going negative.
setup:
    c1.auto_decrement(1000)
loop:
    if c1 == 0:
        c1.pause()
Example 3 — Configures a countdown but starts it paused — call auto_decrement(...) again later to start it ticking.
setup:
    c1.set(10)
    c1.auto_decrement(500)
loop:
    c1.pause()
c1.set(value)
Needs: import counter

Jumps the counter straight to a specific number.

valueThe exact number to set the counter to.
Example 1 — Starts the counter at 100 instead of 0.
setup:
    c1.set(100)
Example 2 — A button can jump the counter back to a specific value.
if i1 == ON:
    c1.set(0)
Example 3 — Sets the starting point, then counts down from there.
setup:
    c1.set(60)
    c1.auto_decrement(1000)

Clock Function

clock_start(hours, minutes, seconds)
Needs: import clock

Sets the clock to a starting time and begins running it.

hours0-23.
minutes0-59.
seconds0-59.
Example 1 — Starts the clock at 12:30:00 and shows the hour.
setup:
    clock_start(12, 30, 0)
loop:
    oled_write(1, left, small, regular, HH)
Example 2 — Starts from midnight; turns o1 on once a minute has passed.
setup:
    clock_start(0, 0, 0)
loop:
    if MM == 1:
        o1 = pwm(100)
Example 3 — Starts just before midnight, to test the hour rolling over.
setup:
    clock_start(23, 59, 55)
HH, MM, SS
Needs: import clock

Three special values that always hold the clock’s current hour, minute, and second — read them directly in a condition, no parentheses needed.

HHThe current hour, 0-23.
MMThe current minute, 0-59.
SSThe current second, 0-59.
Example 1 — Turns o1 on the instant the hour reaches 12.
setup:
    clock_start(9, 0, 0)
loop:
    if HH == 12:
        o1 = pwm(100)
Example 2 — Turns o1 on for exactly the one minute when MM equals 30, then back off.
setup:
    clock_start(0, 0, 0)
loop:
    if MM == 30:
        o1 = pwm(100)
    else:
        o1 = 0
Example 3 — Comparing HH and MM together checks for one exact time, like an alarm.
setup:
    clock_start(7, 55, 0)
loop:
    if HH == 8 and MM == 0:
        bluetooth_write("It's 8:00!")
Example 4 — A night light: on from 10 PM until 6 AM, using HH with >= and < instead of ==.
setup:
    clock_start(0, 0, 0)
loop:
    if HH >= 22 or HH < 6:
        o1 = pwm(100)
    else:
        o1 = 0
clock_speed(real_ms_per_second)
Needs: import clock

Changes how fast the clock runs — how many real milliseconds count as 1 simulated second.

real_ms_per_second1000 = real time. Smaller = faster (e.g. 100 = 10x speed). 1–32767.
Example 1 — Runs the clock 10x faster than real time — handy for testing.
setup:
    clock_start(0, 0, 0)
    clock_speed(100)
Example 2 — Runs at true real-time speed — 1 real second = 1 clock second.
setup:
    clock_start(0, 0, 0)
    clock_speed(1000)
Example 3 — Runs at half speed — 2 real seconds pass for every 1 clock second.
setup:
    clock_start(0, 0, 0)
    clock_speed(2000)
clock_pause()
Needs: import clock

Freezes the clock exactly where it is.

Example 1 — A button freezes the clock, like a stopwatch.
setup:
    clock_start(0, 0, 0)
loop:
    if i1 == ON:
        clock_pause()
Example 2 — Stops itself once 5 minutes have passed.
setup:
    clock_start(0, 5, 0)
loop:
    if MM >= 5:
        clock_pause()
clock_resume()
Needs: import clock

Starts the clock ticking again after clock_pause().

Example 1 — A button starts the clock running again.
setup:
    clock_start(0, 0, 0)
loop:
    clock_pause()
    if i1 == ON:
        clock_resume()
Example 2 — One button pauses, another resumes — like a real stopwatch.
setup:
    clock_start(0, 0, 0)
loop:
    if i1 == ON:
        clock_pause()
    if i2 == ON:
        clock_resume()

Bluetooth & IoT Function

bluetooth_begin()
Needs: import bluetooth

Switches Bluetooth on when the board starts. Goes inside setup: — every Bluetooth program needs it (the editor adds it for you).

Example 1 — Bluetooth starts once at power-on, then the loop reacts to the app.
setup:
    bluetooth_begin()

loop:
    if bluetooth_read_char() == 'A':
        o1 = ON
Example 2 — Starts Bluetooth with your own password.
setup:
    bluetooth_begin()
    set_device_password("5678")
Example 3 — Says hello to the app every second.
setup:
    bluetooth_begin()

loop:
    bluetooth_write("hello")
    wait(1000)
bluetooth_connected()
Needs: import bluetooth · Firmware: 2.15+

Gives 1 while a phone or app is connected (and gave the password), otherwise 0. Needs firmware 2.15+.

Example 1 — Safety stop: the robot stops if the phone disconnects.
if bluetooth_connected() == 0:
    robot_control("S", 0, "S", 0)
Example 2 — A blue light that shows when the app is connected.
if bluetooth_connected() == 1:
    o1 = ON
else:
    o1 = OFF
Example 3 — Waits for the app before the project starts.
while bluetooth_connected() == 0:
    oled_write(1, left, small, regular, "Connect app")
    wait(500)
oled_clear()
bluetooth_write(value)
Needs: import bluetooth

Sends to the app over Bluetooth: a letter ('A'), text ("hello") or a number / variable (temp). Up to 3 numbers / variables in one message (firmware 2.24+): bluetooth_write(angle, distance()) sends "90,35", bluetooth_write(a, b, c) sends "a,b,c" — no text in this form. The same message twice in a row is sent once.

valueA letter in quotes, text up to 32 characters, or a number / variable.
a, b, c2 or 3 numbers / variables, sent together as "a,b" or "a,b,c".
Example 1 — Sends the text hello.
bluetooth_write("hello")
Example 2 — Sends the temperature as a number, e.g. 25.
t = dht_temperature(i1)
bluetooth_write(t)
Example 3 — Sends the letter B when the button is pressed.
if i1 == ON:
    bluetooth_write('B')
bluetooth_read_char()
Needs: import bluetooth · Firmware: 2.18+

The letter the app sent (like a button tap). It lasts one loop cycle, then gives None until the next letter arrives.

Example 1 — Turns o1 on when the letter F arrives.
if bluetooth_read_char() == 'F':
    o1 = ON
Example 2 — Two buttons in the app: 1 = on, 0 = off.
c = bluetooth_read_char()
if c == '1':
    o1 = ON
elif c == '0':
    o1 = OFF
Example 3 — Answers every letter that arrives.
if bluetooth_read_char() != None:
    bluetooth_write("got it")
bluetooth_read_string()
Needs: import bluetooth · Firmware: 2.18+

Text the app sent (up to 32 characters), for one loop cycle. Compare it, show it or send it — it can’t go in a variable.

Example 1 — Opens the door when the app sends the word open.
if bluetooth_read_string() == "open":
    o1 = servo_angle(90)
Example 2 — Shows any text from the app on the LCD.
setup:
    lcd_begin()
lcd_write(1, 1, bluetooth_read_string())
Example 3 — Answers ok to every text.
if bluetooth_read_string() != None:
    bluetooth_write("ok")
bluetooth_read_number()
Needs: import bluetooth · Firmware: 2.18+

A number the app sent (like a slider), for one loop cycle — then None until a new one arrives.

Example 1 — A slider in the app sets the brightness of o1.
n = bluetooth_read_number()
if n != None:
    o1 = pwm(n)
Example 2 — The app turns a servo to any angle.
n = bluetooth_read_number()
if n != None:
    o2 = servo_angle(n)
Example 3 — Sends back double the number.
n = bluetooth_read_number()
if n != None:
    bluetooth_write(n * 2)
x, y = bluetooth_read_position()
Needs: import bluetooth · Firmware: 2.18+

A position from the app: x and y, each −100 to 100 — or x, y, d with its data number (0 if the app sent none; Hand Tracker 2 sends the gesture). None when nothing new arrived this cycle.

Example 1 — Pushing the joystick up makes o1 brighter.
x, y = bluetooth_read_position()
if y != None:
    o1 = pwm(y)
Example 2 — Left / right on the joystick turns a servo.
x, y = bluetooth_read_position()
if x != None:
    o2 = servo_angle(90 + x)
Example 3 — Joystick forward drives the robot forward.
x, y = bluetooth_read_position()
if y != None and y > 50:
    robot_control("F", 80, "F", 80)
Example 4 — With its data (Hand Tracker 2 sends the gesture as d): 1 = light on, 2 = light off.
x, y, d = bluetooth_read_position()
if d == 1:
    o1 = ON
elif d == 2:
    o1 = OFF
r, g, b = bluetooth_read_rgb()
Needs: import bluetooth · Firmware: 2.18+

A colour from the app’s colour picker: red, green, blue, each 0–255. None, None, None when nothing new arrived this cycle.

Example 1 — The RGB LEDs take the colour picked in the app.
r, g, b = bluetooth_read_rgb()
if r != None:
    rgb_hex_color(o1, all, r, g, b)
Example 2 — Uses only the red part to dim a lamp.
r, g, b = bluetooth_read_rgb()
if r != None:
    o1 = pwm(r * 100 / 255)
Example 3 — Says thank you for the colour.
r, g, b = bluetooth_read_rgb()
if r != None:
    bluetooth_write("colour set")
set_device_password("1234")
Needs: import bluetooth · Firmware: 2.13+

Sets the board’s Bluetooth password (4 digits) and saves it. Needs firmware 2.13+.

passwordExactly 4 digits in quotes, e.g. "5678". Phones and the editor must type this to connect.
Example 1 — Gives the board your own password once, when the program starts.
setup:
    set_device_password("5678")
Example 2 — Changes the password when the button is pressed.
if i1 == ON:
    set_device_password("2468")
Example 3 — Safe inside the loop — the board only saves it when it really changes.
setup:
    set_device_password("5678")
loop:
    bluetooth_write("ready")
iot_write(value)
Needs: import iot · Firmware: 2.18+

Sends to the app over the internet: a letter ('A'), text ("hello") or a number / variable (temp). Up to 3 numbers / variables in one message (firmware 2.24+): iot_write(angle, distance()) sends "90,35", iot_write(a, b, c) sends "a,b,c" — no text in this form. The same message twice in a row is sent once.

valueA letter in quotes, text up to 32 characters, or a number / variable.
a, b, c2 or 3 numbers / variables, sent together as "a,b" or "a,b,c".
Example 1 — Sends the text hello.
iot_write("hello")
Example 2 — Sends the temperature as a number, e.g. 25.
t = dht_temperature(i1)
iot_write(t)
Example 3 — Sends the letter B when the button is pressed.
if i1 == ON:
    iot_write('B')
iot_read_char()
Needs: import iot · Firmware: 2.18+

The letter the app sent (like a button tap). It lasts one loop cycle, then gives None until the next letter arrives.

Example 1 — Turns o1 on when the letter F arrives.
if iot_read_char() == 'F':
    o1 = ON
Example 2 — Two buttons in the app: 1 = on, 0 = off.
c = iot_read_char()
if c == '1':
    o1 = ON
elif c == '0':
    o1 = OFF
Example 3 — Answers every letter that arrives.
if iot_read_char() != None:
    iot_write("got it")
iot_read_string()
Needs: import iot · Firmware: 2.18+

Text the app sent (up to 32 characters), for one loop cycle. Compare it, show it or send it — it can’t go in a variable.

Example 1 — Opens the door when the app sends the word open.
if iot_read_string() == "open":
    o1 = servo_angle(90)
Example 2 — Shows any text from the app on the LCD.
setup:
    lcd_begin()
lcd_write(1, 1, iot_read_string())
Example 3 — Answers ok to every text.
if iot_read_string() != None:
    iot_write("ok")
iot_read_number()
Needs: import iot · Firmware: 2.18+

A number the app sent (like a slider), for one loop cycle — then None until a new one arrives.

Example 1 — A slider in the app sets the brightness of o1.
n = iot_read_number()
if n != None:
    o1 = pwm(n)
Example 2 — The app turns a servo to any angle.
n = iot_read_number()
if n != None:
    o2 = servo_angle(n)
Example 3 — Sends back double the number.
n = iot_read_number()
if n != None:
    iot_write(n * 2)
x, y = iot_read_position()
Needs: import iot · Firmware: 2.18+

A position from the app: x and y, each −100 to 100 — or x, y, d with its data number (0 if the app sent none; Hand Tracker 2 sends the gesture). None when nothing new arrived this cycle.

Example 1 — Pushing the joystick up makes o1 brighter.
x, y = iot_read_position()
if y != None:
    o1 = pwm(y)
Example 2 — Left / right on the joystick turns a servo.
x, y = iot_read_position()
if x != None:
    o2 = servo_angle(90 + x)
Example 3 — Joystick forward drives the robot forward.
x, y = iot_read_position()
if y != None and y > 50:
    robot_control("F", 80, "F", 80)
Example 4 — With its data (Hand Tracker 2 sends the gesture as d): 1 = light on, 2 = light off.
x, y, d = iot_read_position()
if d == 1:
    o1 = ON
elif d == 2:
    o1 = OFF
r, g, b = iot_read_rgb()
Needs: import iot · Firmware: 2.18+

A colour from the app’s colour picker: red, green, blue, each 0–255. None, None, None when nothing new arrived this cycle.

Example 1 — The RGB LEDs take the colour picked in the app.
r, g, b = iot_read_rgb()
if r != None:
    rgb_hex_color(o1, all, r, g, b)
Example 2 — Uses only the red part to dim a lamp.
r, g, b = iot_read_rgb()
if r != None:
    o1 = pwm(r * 100 / 255)
Example 3 — Says thank you for the colour.
r, g, b = iot_read_rgb()
if r != None:
    iot_write("colour set")

Robot Function

robot_control(left_dir, left_speed, right_dir, right_speed)
Needs: import motor

Drives both of the rover’s motors at once — one call expresses any movement: straight, reverse, a spin-in-place turn, a curve at any ratio, a full stop, or leaving one motor exactly as it was.

left_dir"F" (forward), "B" (backward), "S" (stop — forces this motor to 0 even if a speed is given), or "X" (do not disturb — leaves this motor completely untouched, pwm ignored). Always in quotes.
left_speed0–100 — the left wheel’s speed. Ignored if left_dir is "S" or "X".
right_dirSame four options as left_dir, for the right wheel.
right_speed0–100 — the right wheel’s speed. Ignored if right_dir is "S" or "X".
Example 1 — Both wheels forward, full speed — drives straight ahead.
robot_control("F", 100, "F", 100)
Example 2 — Both wheels backward, full speed — reverses straight.
robot_control("B", 100, "B", 100)
Example 3 — Left backward, right forward — spins in place, turning left.
robot_control("B", 100, "F", 100)
Example 4 — Left forward, right backward — spins in place, turning right.
robot_control("F", 100, "B", 100)
Example 5 — Both forward, but the right wheel is faster — arcs left while still moving.
robot_control("F", 60, "F", 100)
Example 6 — Both forward, left wheel faster — arcs right while still moving.
robot_control("F", 100, "F", 60)
Example 7 — A slow, gentle crawl forward — useful for careful maneuvering.
robot_control("F", 30, "F", 30)
Example 8 — Obstacle avoidance: backs away from anything closer than 20cm, otherwise drives forward.
if distance() < 20:
    robot_control("B", 60, "B", 60)
else:
    robot_control("F", 80, "F", 80)
Example 9 — A button acts like a dead-man’s switch — the robot only moves while it’s held down.
if i1 == ON:
    robot_control("F", 100, "F", 100)
else:
    robot_control("F", 0, "F", 0)
Example 10 — Drives forward, then spins a quarter turn, four times in a row — traces out a rough square.
repeat(4):
    robot_control("F", 100, "F", 100)
    wait(1000)
    robot_control("B", 100, "F", 100)
    wait(500)
Example 11 — Ramps smoothly from a stop up to full speed, 10% at a time, using a variable instead of a fixed number.
speed = 0
repeat(10):
    speed = speed + 10
    robot_control("F", speed, "F", speed)
    wait(200)
Example 12 — Both reversing, but the LEFT wheel is faster this time — curves right while backing up (curving while reversing flips which side is "faster", compared to driving forward).
robot_control("B", 100, "B", 60)
Example 13 — A simple line-follower shape: drives straight when both sensors agree, leans toward whichever sensor is off, stops if neither is triggered.
if i1 == ON and i2 == ON:
    robot_control("F", 80, "F", 80)
elif i1 == ON:
    robot_control("F", 40, "F", 80)
elif i2 == ON:
    robot_control("F", 80, "F", 40)
else:
    robot_control("F", 0, "F", 0)
Example 14 — Stops both motors completely — the same as robot_control("F", 0, "F", 0), just more explicit about the intent.
robot_control("S", 0, "S", 0)
Example 15 — Controls only the LEFT motor with a button — "X" leaves the right motor completely alone, whatever it was already doing.
if i1 == ON:
    robot_control("F", 70, "X", 0)
else:
    robot_control("S", 0, "X", 0)
motor_control_right(direction, speed)
Needs: import motor

Drives just the RIGHT motor — the same o3/o4 pins robot_control(...) uses for its right side, controlled on their own instead of alongside the left motor.

direction"F" (forward), "B" (backward), or "S" (stop — forces this motor to 0 even if a speed is given). Always in quotes.
speed0–100 — the wheel’s speed. Ignored if direction is "S".
Example 1 — Right wheel forward at 70% speed.
motor_control_right("F", 70)
Example 2 — Stops just the right motor.
motor_control_right("S", 0)
Example 3 — Right forward, left backward — spins in place, using two separate calls instead of one robot_control(...).
motor_control_right("F", 60)
motor_control_left("B", 60)
motor_control_left(direction, speed)
Needs: import motor

Drives just the LEFT motor — the same o5/o6 pins robot_control(...) uses for its left side, controlled on their own instead of alongside the right motor.

direction"F" (forward), "B" (backward), or "S" (stop — forces this motor to 0 even if a speed is given). Always in quotes.
speed0–100 — the wheel’s speed. Ignored if direction is "S".
Example 1 — Left wheel forward at 70% speed.
motor_control_left("F", 70)
Example 2 — Stops just the left motor.
motor_control_left("S", 0)
Example 3 — A button controls just the left wheel, independent of whatever the right wheel is doing.
if i1 == ON:
    motor_control_left("F", 50)
else:
    motor_control_left("S", 0)
robot_forward(speed)
Needs: import motor · both motors set up · any firmware

Drives the robot straight ahead: both wheels forward at the same speed. Works like robot_control(...) with the directions filled in.

speed0–100: how fast the wheels turn (a number or a variable).
Example 1 — Straight ahead at 80% speed.
robot_forward(80)
robot_backward(speed)
Needs: import motor · both motors set up · any firmware

Drives the robot straight back: both wheels backward at the same speed. Works like robot_control(...) with the directions filled in.

speed0–100: how fast the wheels turn (a number or a variable).
Example 1 — Reverses at 60% speed.
robot_backward(60)
robot_left(speed)
Needs: import motor · both motors set up · any firmware

Spins the robot to the LEFT on the spot: right wheel forward, left wheel backward, same speed. Works like robot_control(...) with the directions filled in.

speed0–100: how fast the wheels turn (a number or a variable).
Example 1 — Spins left at 60% speed.
robot_left(60)
robot_right(speed)
Needs: import motor · both motors set up · any firmware

Spins the robot to the RIGHT on the spot: left wheel forward, right wheel backward, same speed. Works like robot_control(...) with the directions filled in.

speed0–100: how fast the wheels turn (a number or a variable).
Example 1 — Spins right at 60% speed.
robot_right(60)
robot_arc_left(speed)
Needs: import motor · both motors set up · any firmware

Drives forward in a curve to the LEFT: the right wheel at the speed, the left (inner) wheel at half of it. Works like robot_control(...) with the directions filled in.

speed0–100: the outer wheel’s speed; the inner wheel turns at half of it.
Example 1 — Right wheel 80%, left wheel 40%: a smooth left curve.
robot_arc_left(80)
robot_arc_right(speed)
Needs: import motor · both motors set up · any firmware

Drives forward in a curve to the RIGHT: the left wheel at the speed, the right (inner) wheel at half of it. Works like robot_control(...) with the directions filled in.

speed0–100: the outer wheel’s speed; the inner wheel turns at half of it.
Example 1 — Left wheel 80%, right wheel 40%: a smooth right curve.
robot_arc_right(80)
robot_stop()
Needs: import motor · both motors set up · any firmware

Stops both wheels. Works like robot_control(...) with the directions filled in.

Example 1 — Drive for 2 seconds, then stop.
robot_forward(80)
wait(2000)
robot_stop()

5.3 Firmware needed

The board must have this firmware (or newer) for a program that uses the feature. TinkerPy Code shows the needed version when uploading. The newest board firmware is 2.26 (the board password for WiFi upload too, shown on the CODE DOWNLOAD screens; 2.25 added wireless_iot — board to board over the internet; 2.24 added voltage(), text variables, joining text with + and wireless board to board), so update boards to 2.25. Upload checks the board’s live firmware and says so when it is too old.

FirmwareAdds
2.13set_device_password
2.14servo_flip
2.15random, while, break, analog_read, bluetooth_connected
2.16OLED and LCD functions (oled_…, lcd_…)
2.17RGB LEDs (rgb_…)
2.18bluetooth_read_number / string / position / rgb, iot_read_…, iot_write(text), joystick
2.19buzzer_play, TV remote, OLED eye / emoji animations, position data
2.20oled_write(line, align, size, weight, value)
2.23TV remote: the 29 general keys (remote_read) and remote_read_string — learn the remote again after updating
2.24voltage() (volts 0.00 – 3.30, decimals like 1.6), Debug → Analog Input, text variables, joining with +, wireless (import wireless: TP00000002.connect() / send / read …, wireless_send_all, wireless_read_any)
2.25wireless_iot (import wireless_iot: TP00000002_iot.connect() / send / read …, wireless_iot_send_all, wireless_iot_read_any — board to board over the internet)
2.29buzzer_play_background, buzzer_stop_background, is_buzzer_playing (TinkerPy Mega)
2.26 invert(o2) (reading an output back), WiFi upload asks for the board password (the 4 digits on the CODE DOWNLOAD screen, the same as Bluetooth); set_device_password("5678") changes it (was bluetooth_password)

Part 6 — Complete example projects

45 complete programs, each checked by the real TinkerPy compiler. Use them as patterns for structure, wiring and style.

Basic

Blink an LED

The classic first project: an LED turns on and off every half second.

Wiring: LED on o1 (long leg to o1, short leg to GND).

# ===== Blink an LED =====
# LED on o1

# This code block executes forever

loop:
    o1 = ON
    wait(500)
    o1 = OFF
    wait(500)

Push Button Light

Hold the button and the LED glows. Let go and it switches off.

Wiring: Push button on i1, LED on o1.

# ===== Push Button Light =====
# Button on i1, LED on o1

loop:
    if i1 == ON:
        o1 = ON
    else:
        o1 = OFF

Traffic Light

Red, yellow and green LEDs change just like a real traffic signal.

Wiring: Red LED on o1, yellow LED on o2, green LED on o3.

# ===== Traffic Light =====
# Red o1, Yellow o2, Green o3

loop:
    # Red - stop
    o1 = ON
    wait(4000)
    o1 = OFF
    # Green - go
    o3 = ON
    wait(4000)
    o3 = OFF
    # Yellow - get ready to stop
    o2 = ON
    wait(1500)
    o2 = OFF

Breathing LED

The LED slowly fades in and out, like it is breathing.

Wiring: LED on o1.

# ===== Breathing LED =====
# LED on o1 fades in and out

loop:
    output_increment_till(o1, 0, 100, 5, 40)
    output_decrement_till(o1, 100, 0, 5, 40)
    wait(300)

Toggle Switch

Press the button once to switch the light on, press again to switch it off.

Wiring: Push button on i1, LED on o1.

# ===== Toggle Switch =====
# Each press of i1 flips the LED on o1

loop:
    if i1 == ON:
        output_flip(o1, 0, 100)
        # wait until the button is let go, so one press = one flip
        wait(300)

Servo

Servo Sweep

The servo arm sweeps smoothly from 0° to 180° and back again.

Wiring: Servo signal wire on o1 (brown/black to GND, red to 5V).

# ===== Servo Sweep =====
# Servo on o1

import servo

setup:
    o1 = set_function(servo)  # servo

loop:
    servo_increment_till(o1, 0, 180, 5, 20)
    servo_decrement_till(o1, 180, 0, 5, 20)

Button Gate

Press the button to open the gate. It closes again after 3 seconds.

Wiring: Servo (the gate arm) on o1, push button on i1.

# ===== Button Gate =====
# Servo gate on o1, button on i1

import servo

setup:
    o1 = set_function(servo)  # servo
    servo_write_angle(o1, 0)

loop:
    if i1 == ON:
        servo_write_angle(o1, 90)
        wait(3000)
        servo_write_angle(o1, 0)

Radar Scanner

The servo scans left and right forever, like a radar dish.

Wiring: Servo on o1.

# ===== Radar Scanner =====
# Servo on o1 scans by itself

import servo

setup:
    o1 = set_function(servo)  # servo
    servo_scan_on(o1, 0, 180, 5, 20)

loop:
    wait(1000)

Waving Robot Hand

A cardboard hand on the servo waves hello three times when you press the button.

Wiring: Servo with a cardboard hand on o1, push button on i1.

# ===== Waving Robot Hand =====
# Servo hand on o1, button on i1

import servo

setup:
    o1 = set_function(servo)  # servo
    servo_write_angle(o1, 90)

loop:
    if i1 == ON:
        repeat(3):
            servo_write_angle(o1, 45)
            wait(300)
            servo_write_angle(o1, 135)
            wait(300)
        servo_write_angle(o1, 90)

Mirror Servos

Two servos move like a pair of wings: when one goes up, the other goes down.

Wiring: Servo 1 on o1, servo 2 on o2.

# ===== Mirror Servos =====
# Servos on o1 and o2 move like wings

import servo

setup:
    o1 = set_function(servo)  # servo
    o2 = set_function(servo)  # servo
    servo_sync_reverse(o1, o2)

loop:
    servo_increment_till(o1, 30, 150, 5, 25)
    servo_decrement_till(o1, 150, 30, 5, 25)

Ultrasonic

Distance Alarm

A buzzer beeps when something comes closer than 20 cm.

Wiring: Ultrasonic sensor: Trig on i3, Echo on i4. Buzzer on o1.

# ===== Distance Alarm =====
# Ultrasonic (Trig i3, Echo i4), buzzer on o1

import ultrasonic

setup:
    i3 = set_function(ultrasonic_TX)  # cannot be changed
    i4 = set_function(ultrasonic_RX)  # cannot be changed

loop:
    if distance() < 20:
        o1 = ON
    else:
        o1 = OFF

Parking Sensor

Beeps faster and faster as a car gets closer to the wall, just like a real parking sensor.

Wiring: Ultrasonic sensor: Trig on i3, Echo on i4. Buzzer on o1.

# ===== Parking Sensor =====
# Ultrasonic (Trig i3, Echo i4), buzzer on o1

import ultrasonic

setup:
    i3 = set_function(ultrasonic_TX)  # cannot be changed
    i4 = set_function(ultrasonic_RX)  # cannot be changed

loop:
    d = distance()
    if d < 10:
        o1 = ON
    elif d < 30:
        o1 = ON
        wait(100)
        o1 = OFF
        wait(100)
    elif d < 60:
        o1 = ON
        wait(100)
        o1 = OFF
        wait(400)
    else:
        o1 = OFF

Smart Dustbin

The dustbin lid opens by itself when your hand comes near, then closes.

Wiring: Ultrasonic sensor: Trig on i3, Echo on i4 (facing up). Servo for the lid on o1.

# ===== Smart Dustbin =====
# Ultrasonic (Trig i3, Echo i4), lid servo on o1

import ultrasonic
import servo

setup:
    o1 = set_function(servo)  # servo
    i3 = set_function(ultrasonic_TX)  # cannot be changed
    i4 = set_function(ultrasonic_RX)  # cannot be changed
    servo_write_angle(o1, 0)

loop:
    if distance() < 15:
        servo_write_angle(o1, 100)
        wait(3000)
        servo_write_angle(o1, 0)

Water Tank Level

Shows how full a water tank is with 3 LEDs. The sensor looks down at the water.

Wiring: Ultrasonic sensor at the top of the tank: Trig on i3, Echo on i4. LEDs on o1 (low), o2 (half), o3 (full).

# ===== Water Tank Level =====
# Ultrasonic looks down at the water; LEDs o1 o2 o3

import ultrasonic

setup:
    i3 = set_function(ultrasonic_TX)  # cannot be changed
    i4 = set_function(ultrasonic_RX)  # cannot be changed

loop:
    # small distance = water is near the top = tank is full
    d = distance()
    o1 = ON
    if d < 20:
        o2 = ON
    else:
        o2 = OFF
    if d < 8:
        o3 = ON
    else:
        o3 = OFF
    wait(500)

Touchless Hand Wash

A small pump runs for 2 seconds when hands come under the tap. No touching needed!

Wiring: Ultrasonic sensor under the tap: Trig on i3, Echo on i4. Small 5V pump (through a driver) on o1.

# ===== Touchless Hand Wash =====
# Ultrasonic (Trig i3, Echo i4), pump on o1

import ultrasonic

setup:
    i3 = set_function(ultrasonic_TX)  # cannot be changed
    i4 = set_function(ultrasonic_RX)  # cannot be changed

loop:
    if distance() < 12:
        o1 = ON
        wait(2000)
        o1 = OFF
        # wait for the hands to move away
        wait(1500)

Wireless (two boards)

Each program goes to its own board; each lists the OTHER board’s ID. Firmware 2.24.

Wireless Doorbell — button board

Press the button: the other board rings. A warning LED shows when the bell board did not get it.

Wiring: Push button on i1, LED on o1. Board TP00000001.

# ===== Wireless Doorbell — the button board (TP00000001) =====
# Button on i1. Upload this to TP00000001.
import wireless

setup:
    TP00000002.connect()   # the bell board

loop:
    if i1 == ON:
        ok = TP00000002.send("RING")
        if ok == 0:
            o1 = ON          # not delivered: warning LED
        else:
            o1 = OFF
        wait(300)

Wireless Doorbell — bell board

Rings and shows “Visitor!” when the button board sends RING.

Wiring: Passive buzzer on o1, OLED (SDA o7, SCL o8). Board TP00000002.

# ===== Wireless Doorbell — the bell board (TP00000002) =====
# Passive buzzer on o1, OLED. Upload this to TP00000002.
import wireless

setup:
    TP00000001.connect()   # the button board
    o1 = set_function(passive_buzzer)
    oled_begin()

loop:
    msg = TP00000001.read()
    if msg == "RING":
        oled_write(1, center, medium, bold, "Visitor!")
        buzzer_play(o1, "door_bell")
    if TP00000001.connected() == 0:
        oled_write(4, left, small, regular, "Waiting for button")

Wireless IoT (two boards over the internet)

Each program goes to its own board; each lists the OTHER board’s ID with _iot. Both boards need WiFi. Firmware 2.25.

Internet Doorbell — button board

Press the button: the other board rings, wherever it is. An LED shows when the bell board is offline.

Wiring: Push button on i1, LED on o1. Board TP00000001.

# ===== Internet Doorbell — the button board (TP00000001) =====
# Button on i1. Upload this to TP00000001. Both boards need WiFi.
import wireless_iot

setup:
    TP00000002_iot.connect()   # the bell board, anywhere

loop:
    if i1 == ON:
        ok = TP00000002_iot.send("RING")
        if ok == 0:
            o1 = ON          # the bell board is offline
        else:
            o1 = OFF
        wait(1000)

Internet Doorbell — bell board

Rings and shows “Visitor!” when the button board sends RING.

Wiring: Passive buzzer on o1, OLED (SDA o7, SCL o8). Board TP00000002.

# ===== Internet Doorbell — the bell board (TP00000002) =====
# Passive buzzer on o1, OLED. Upload this to TP00000002.
import wireless_iot

setup:
    TP00000001_iot.connect()   # the button board
    o1 = set_function(passive_buzzer)
    oled_begin()

loop:
    msg = TP00000001_iot.read()
    if msg == "RING":
        oled_write(1, center, medium, bold, "Visitor!")
        buzzer_play(o1, "door_bell")
    if TP00000001_iot.connected() == 0:
        oled_write(4, left, small, regular, "Button board offline")

Clock

Digital Clock

Shows the time (hours, minutes, seconds) on the OLED display.

Wiring: 0.96" OLED display (SDA o7, SCL o8). Change the start time in setup. · Firmware 2.20+

# ===== Digital Clock =====
# Set the start time below, shown on the OLED

import clock
import oled_display

setup:
    oled_begin()  # starts the OLED
    o7 = set_function(SDA)  # cannot be changed
    o8 = set_function(SCL)  # cannot be changed
    clock_start(10, 30, 0)

loop:
    oled_write(1, left, small, regular, "Time now")
    oled_write(2, left, small, regular, HH)
    oled_write(3, left, small, regular, MM)
    oled_write(4, left, small, regular, SS)
    wait(500)

School Bell

Rings a bell (buzzer) at the start of each period: 9:00, 9:45 and 10:30.

Wiring: Buzzer on o1. Set the clock to the real time in setup.

# ===== School Bell =====
# Buzzer on o1 rings at period times

import clock

setup:
    clock_start(8, 59, 50)

loop:
    if SS == 0:
        if HH == 9 and MM == 0:
            o1 = ON
            wait(3000)
            o1 = OFF
        if HH == 9 and MM == 45:
            o1 = ON
            wait(3000)
            o1 = OFF
        if HH == 10 and MM == 30:
            o1 = ON
            wait(3000)
            o1 = OFF
    wait(500)

Night Lamp

The lamp switches on by itself at 7 PM and off at 6 AM.

Wiring: Lamp/LED on o1. Set the clock to the real time in setup.

# ===== Night Lamp =====
# Lamp on o1, on from 7 PM to 6 AM

import clock

setup:
    clock_start(18, 59, 50)

loop:
    if HH >= 19 or HH < 6:
        o1 = ON
    else:
        o1 = OFF
    wait(1000)

Plant Watering Timer

Waters the plants for 10 seconds every morning at 7:00.

Wiring: Small water pump (through a driver) on o1. Set the clock to the real time in setup.

# ===== Plant Watering Timer =====
# Pump on o1 runs at 7:00 every day

import clock

setup:
    clock_start(6, 59, 50)

loop:
    if HH == 7 and MM == 0 and SS == 0:
        o1 = ON
        wait(10000)
        o1 = OFF
    wait(500)

Stopwatch

Button i1 starts and stops the stopwatch, button i2 resets it to zero.

Wiring: Start/stop button on i1, reset button on i2, OLED display (SDA o7, SCL o8). · Firmware 2.20+

# ===== Stopwatch =====
# i1 start/stop, i2 reset, time on the OLED

import clock
import oled_display

setup:
    oled_begin()  # starts the OLED
    o7 = set_function(SDA)  # cannot be changed
    o8 = set_function(SCL)  # cannot be changed
    clock_start(0, 0, 0)
    clock_pause()
    running = 0

loop:
    if i1 == ON:
        if running == 0:
            clock_resume()
            running = 1
        else:
            clock_pause()
            running = 0
        wait(300)
    if i2 == ON:
        clock_start(0, 0, 0)
        clock_pause()
        running = 0
    oled_write(1, left, small, regular, "Stopwatch")
    oled_write(2, left, small, regular, MM)
    oled_write(3, left, small, regular, SS)
    wait(100)

OLED

Hello Display

Your first OLED project: shows a greeting on the screen.

Wiring: 0.96" OLED display (SDA o7, SCL o8). · Firmware 2.20+

# ===== Hello Display =====
# OLED on o7 (SDA) / o8 (SCL)

import oled_display

setup:
    oled_begin()  # starts the OLED
    o7 = set_function(SDA)  # cannot be changed
    o8 = set_function(SCL)  # cannot be changed
    oled_write(1, center, medium, bold, "Hello!")  # big + bold, uses lines 1-2
    oled_write(3, center, small, regular, "I am TinkerPy")
    oled_write(4, center, small, regular, "Let's build!")

loop:
    wait(1000)

Button Counter

Counts how many times the button is pressed and shows the number.

Wiring: Push button on i1 (count), i2 (reset). OLED display (SDA o7, SCL o8). · Firmware 2.20+

# ===== Button Counter =====
# i1 counts, i2 resets, number on the OLED

import oled_display
import counter

setup:
    oled_begin()  # starts the OLED
    o7 = set_function(SDA)  # cannot be changed
    o8 = set_function(SCL)  # cannot be changed
    oled_write(1, left, small, bold, "Presses:")

loop:
    if i1 == ON:
        c1.increment()
        wait(250)
    if i2 == ON:
        c1.clear()
    oled_write(2, center, large, bold, c1)  # a big number on lines 2-3

Distance Meter

A digital measuring tape: shows the distance in cm on the screen.

Wiring: Ultrasonic sensor: Trig on i3, Echo on i4. OLED display (SDA o7, SCL o8). · Firmware 2.20+

# ===== Distance Meter =====
# Ultrasonic (Trig i3, Echo i4) + OLED

import oled_display
import ultrasonic

setup:
    oled_begin()  # starts the OLED
    i3 = set_function(ultrasonic_TX)  # cannot be changed
    i4 = set_function(ultrasonic_RX)  # cannot be changed
    o7 = set_function(SDA)  # cannot be changed
    o8 = set_function(SCL)  # cannot be changed
    oled_write(1, center, small, bold, "Distance (cm)")

loop:
    oled_write(2, center, large, bold, distance())  # a big number on lines 2-3
    wait(300)

Weather Station

Shows the room temperature and humidity from a DHT11 sensor.

Wiring: DHT11 sensor data pin on i3. OLED display (SDA o7, SCL o8). · Firmware 2.20+

# ===== Weather Station =====
# DHT11 on i3, readings on the OLED

import oled_display
import dht11

setup:
    oled_begin()  # starts the OLED
    i3 = set_function(dht11)
    o7 = set_function(SDA)  # cannot be changed
    o8 = set_function(SCL)  # cannot be changed

loop:
    oled_write(1, left, small, bold, "Temp (C)")
    oled_write(2, right, small, regular, dht_temperature(i3))
    oled_write(3, left, small, bold, "Humidity (%)")
    oled_write(4, right, small, regular, dht_humidity(i3))
    wait(2000)

Countdown Timer

Press the button to start a 10-second countdown. A buzzer beeps at zero.

Wiring: Start button on i1, buzzer on o1, OLED display (SDA o7, SCL o8). · Firmware 2.20+

# ===== Countdown Timer =====
# i1 starts, buzzer on o1, OLED shows the count

import oled_display
import counter

setup:
    oled_begin()  # starts the OLED
    o7 = set_function(SDA)  # cannot be changed
    o8 = set_function(SCL)  # cannot be changed
    c1.set(10)
    oled_write(1, center, small, regular, "Press to start")

loop:
    if i1 == ON:
        c1.set(10)
        c1.auto_decrement(1000)
        oled_write(1, center, small, regular, "Counting down")
    oled_write(2, center, large, bold, c1)  # a big number on lines 2-3
    if c1 == 0:
        c1.pause()
        oled_write(1, center, small, bold, "Time up!")
        o1 = ON
        wait(1000)
        o1 = OFF
        c1.set(10)

Bluetooth

Bluetooth Light

Switch an LED on and off from your phone with Bluetooth.

Wiring: LED on o1. Connect with the TinkerPy App and send 1 (on) or 0 (off). · Firmware 2.18+

# ===== Bluetooth Light =====
# Send 1 / 0 from the TinkerPy App

import bluetooth

setup:
    bluetooth_begin()  # switches Bluetooth on when the board starts

loop:
    bt_data = bluetooth_read_char()
    if bt_data == '1':
        o1 = ON
    elif bt_data == '0':
        o1 = OFF

Bluetooth Robot Car

Drive the robot car from your phone: F, B, L, R and S (stop).

Wiring: Motors on o3–o6 (motor driver). Use the arrow buttons in the TinkerPy App. · Firmware 2.18+

# ===== Bluetooth Robot Car =====
# F B L R S from the TinkerPy App

import bluetooth
import motor

setup:
    o3 = set_function(motor_right_forward)  # cannot be changed
    o4 = set_function(motor_right_backward)  # cannot be changed
    o5 = set_function(motor_left_forward)  # cannot be changed
    o6 = set_function(motor_left_backward)  # cannot be changed
    bluetooth_begin()  # switches Bluetooth on when the board starts

loop:
    bt_data = bluetooth_read_char()
    if bt_data == 'F':
        robot_control("F", 80, "F", 80)
    elif bt_data == 'B':
        robot_control("B", 80, "B", 80)
    elif bt_data == 'L':
        robot_control("B", 70, "F", 70)
    elif bt_data == 'R':
        robot_control("F", 70, "B", 70)
    elif bt_data == 'S':
        robot_control("S", 0, "S", 0)

Bluetooth Door Lock

A servo locks and unlocks a door when the phone sends U (unlock) or L (lock).

Wiring: Servo (the lock) on o1. Send U or L from the TinkerPy App. · Firmware 2.18+

# ===== Bluetooth Door Lock =====
# U unlocks, L locks; servo on o1

import bluetooth
import servo

setup:
    o1 = set_function(servo)  # servo
    bluetooth_begin()  # switches Bluetooth on when the board starts
    servo_write_angle(o1, 0)

loop:
    bt_data = bluetooth_read_char()
    if bt_data == 'U':
        servo_write_angle(o1, 90)
        bluetooth_write("Door unlocked")
    elif bt_data == 'L':
        servo_write_angle(o1, 0)
        bluetooth_write("Door locked")

Bluetooth Doorbell

Press the doorbell button and a message pops up on your phone.

Wiring: Push button on i1, buzzer on o1. Open the TinkerPy App to see the messages.

# ===== Bluetooth Doorbell =====
# Button i1 sends a message to the phone

import bluetooth

setup:
    bluetooth_begin()  # switches Bluetooth on when the board starts

loop:
    if i1 == ON:
        o1 = ON
        bluetooth_write("Someone is at the door!")
        wait(500)
        o1 = OFF
        wait(1000)

Bluetooth Fan Speed

Choose the fan speed from your phone: 0 (off), 1 (slow), 2 (medium), 3 (fast).

Wiring: Small DC fan (through a driver) on o1. Send 0–3 from the TinkerPy App. · Firmware 2.18+

# ===== Bluetooth Fan Speed =====
# Send 0, 1, 2 or 3 from the TinkerPy App

import bluetooth

setup:
    bluetooth_begin()  # switches Bluetooth on when the board starts

loop:
    bt_data = bluetooth_read_char()
    if bt_data == '0':
        o1 = pwm(0)
    elif bt_data == '1':
        o1 = pwm(40)
    elif bt_data == '2':
        o1 = pwm(70)
    elif bt_data == '3':
        o1 = pwm(100)

IoT

IoT Light Switch

Switch a light on and off from anywhere using the internet.

Wiring: LED or relay on o1. Connect the TinkerPy App over IoT (Device ID + PIN) and send 1 / 0. · Firmware 2.18+

# ===== IoT Light Switch =====
# Send 1 / 0 from the TinkerPy App (IoT)

import iot

loop:
    iot_data = iot_read_char()
    if iot_data == '1':
        o1 = ON
        iot_write("Light is ON")
    elif iot_data == '0':
        o1 = OFF
        iot_write("Light is OFF")

IoT Door Alert

Sends a message to the app whenever the door is opened.

Wiring: Door switch (or button) on i1. Open the TinkerPy App (IoT) to see alerts. · Firmware 2.18+

# ===== IoT Door Alert =====
# Door switch on i1 sends an alert

import iot

loop:
    if i1 == ON:
        iot_write("Door opened!")
        wait(3000)

IoT Room Monitor

Sends the room temperature and humidity to the app every 10 seconds.

Wiring: DHT11 data pin on i3. The app shows channel 1 (temperature) and channel 2 (humidity). · Firmware 2.18+

# ===== IoT Room Monitor =====
# DHT11 on i3 → app channels 1 and 2

import iot
import dht11

setup:
    i3 = set_function(dht11)

loop:
    if dht_temperature(i3) > 30:
        iot_write("It is hot!")
    if dht_temperature(i3) > 25:
        iot_write("warm")
    else:
        iot_write("cool")
    if dht_humidity(i3) > 70:
        iot_write("humid")
    else:
        iot_write("dry")
    wait(10000)

IoT Smart Plug

Turn a plug on or off from the app, or with the button on the board.

Wiring: Relay module on o1, button on i1. Send 1 / 0 from the TinkerPy App (IoT). · Firmware 2.18+

# ===== IoT Smart Plug =====
# App 1/0 or button i1 switches the relay on o1

import iot

loop:
    iot_data = iot_read_char()
    if iot_data == '1':
        o1 = ON
        iot_write("on")
    elif iot_data == '0':
        o1 = OFF
        iot_write("off")
    if i1 == ON:
        output_flip(o1, 0, 100)
        iot_write("Switched by button")
        wait(300)

IoT Garden Watering

Start watering from the app (W), stop it (S). The app hears when the pump starts and stops.

Wiring: Water pump (through a driver) on o1. Send W / S from the TinkerPy App (IoT). · Firmware 2.18+

# ===== IoT Garden Watering =====
# W starts, S stops the pump on o1

import iot

loop:
    iot_data = iot_read_char()
    if iot_data == 'W':
        o1 = ON
        iot_write("Watering started")
    elif iot_data == 'S':
        o1 = OFF
        iot_write("Watering stopped")

Robotics

Robot Dance

The robot moves forward, back, and spins — a little dance!

Wiring: Motors on o3–o6 through the motor driver.

# ===== Robot Dance =====
# Motors on o3-o6

import motor

setup:
    o3 = set_function(motor_right_forward)  # cannot be changed
    o4 = set_function(motor_right_backward)  # cannot be changed
    o5 = set_function(motor_left_forward)  # cannot be changed
    o6 = set_function(motor_left_backward)  # cannot be changed

loop:
    robot_control("F", 70, "F", 70)
    wait(1000)
    robot_control("B", 70, "B", 70)
    wait(1000)
    robot_control("F", 70, "B", 70)
    wait(800)
    robot_control("B", 70, "F", 70)
    wait(800)
    robot_control("S", 0, "S", 0)
    wait(1500)

Obstacle Avoider

The robot drives forward and turns away when something is in front of it.

Wiring: Motors on o3–o6. Ultrasonic sensor at the front: Trig on i3, Echo on i4.

# ===== Obstacle Avoider =====
# Motors o3-o6, ultrasonic Trig i3 / Echo i4

import motor
import ultrasonic

setup:
    o3 = set_function(motor_right_forward)  # cannot be changed
    o4 = set_function(motor_right_backward)  # cannot be changed
    o5 = set_function(motor_left_forward)  # cannot be changed
    o6 = set_function(motor_left_backward)  # cannot be changed
    i3 = set_function(ultrasonic_TX)  # cannot be changed
    i4 = set_function(ultrasonic_RX)  # cannot be changed

loop:
    if distance() < 20:
        robot_control("S", 0, "S", 0)
        wait(200)
        robot_control("B", 60, "B", 60)
        wait(400)
        robot_control("F", 70, "B", 70)
        wait(500)
    else:
        robot_control("F", 70, "F", 70)

Line Follower

Follows a black line on the floor using two IR sensors.

Wiring: Motors on o3–o6. Left IR sensor on i1, right IR sensor on i2 (ON = sees the black line).

# ===== Line Follower =====
# IR left i1, IR right i2, motors o3-o6

import motor

setup:
    o3 = set_function(motor_right_forward)  # cannot be changed
    o4 = set_function(motor_right_backward)  # cannot be changed
    o5 = set_function(motor_left_forward)  # cannot be changed
    o6 = set_function(motor_left_backward)  # cannot be changed

loop:
    if i1 == OFF and i2 == OFF:
        robot_control("F", 60, "F", 60)
    elif i1 == ON and i2 == OFF:
        # line is on the left - turn left
        robot_control("S", 0, "F", 60)
    elif i1 == OFF and i2 == ON:
        # line is on the right - turn right
        robot_control("F", 60, "S", 0)
    else:
        robot_control("S", 0, "S", 0)

Square Path

The robot drives in a square: forward, turn, forward, turn…

Wiring: Motors on o3–o6. Change the turn time until the robot turns exactly 90°.

# ===== Square Path =====
# Motors on o3-o6

import motor

setup:
    o3 = set_function(motor_right_forward)  # cannot be changed
    o4 = set_function(motor_right_backward)  # cannot be changed
    o5 = set_function(motor_left_forward)  # cannot be changed
    o6 = set_function(motor_left_backward)  # cannot be changed

loop:
    repeat(4):
        robot_control("F", 70, "F", 70)
        wait(1500)
        robot_control("F", 70, "B", 70)
        wait(550)
    robot_control("S", 0, "S", 0)
    wait(3000)

Button Remote Robot

Two buttons steer the robot: both = forward, one = turn that way.

Wiring: Motors on o3–o6. Left button on i1, right button on i2.

# ===== Button Remote Robot =====
# i1 + i2 steer, motors o3-o6

import motor

setup:
    o3 = set_function(motor_right_forward)  # cannot be changed
    o4 = set_function(motor_right_backward)  # cannot be changed
    o5 = set_function(motor_left_forward)  # cannot be changed
    o6 = set_function(motor_left_backward)  # cannot be changed

loop:
    if i1 == ON and i2 == ON:
        robot_control("F", 80, "F", 80)
    elif i1 == ON:
        robot_control("F", 30, "F", 80)
    elif i2 == ON:
        robot_control("F", 80, "F", 30)
    else:
        robot_control("S", 0, "S", 0)

Motion (MPU6050)

Spirit Level

Shows how much the board is tilted and lights an LED when it lies perfectly flat.

Wiring: MPU6050 and OLED on o7 (SDA) / o8 (SCL), LED on o1. Keep the board still for the first second after power-on. · Firmware 2.20+

# ===== Spirit Level =====
# MPU6050 + OLED on o7/o8, LED on o1

import mpu6050
import oled_display

setup:
    o7 = set_function(SDA)  # cannot be changed
    o8 = set_function(SCL)  # cannot be changed
    oled_begin()  # starts the OLED

loop:
    oled_clear()
    oled_write(1, left, small, regular, "Tilt front / side")
    oled_write(2, left, small, regular, tilt_x())
    oled_write(3, left, small, regular, tilt_y())
    if tilt_direction() == 'N':
        oled_write(4, left, small, regular, "Level!")
        o1 = ON
    else:
        oled_write(4, left, small, regular, "Tilted")
        o1 = OFF
    wait(200)

Exact Turn Robot

The robot drives forward, then uses the gyro to turn exactly 90° — a perfect square every time.

Wiring: MPU6050 on o7/o8 (flat on the robot), motors on o3–o6.

# ===== Exact Turn Robot =====
# MPU6050 on o7/o8, motors on o3-o6

import mpu6050
import motor

setup:
    o7 = set_function(SDA)  # cannot be changed
    o8 = set_function(SCL)  # cannot be changed
    o3 = set_function(motor_right_forward)  # cannot be changed
    o4 = set_function(motor_right_backward)  # cannot be changed
    o5 = set_function(motor_left_forward)  # cannot be changed
    o6 = set_function(motor_left_backward)  # cannot be changed

loop:
    # drive straight
    robot_control("F", 70, "F", 70)
    wait(1500)
    # turn right until the gyro says 90 degrees
    reset_turn()
    robot_control("F", 60, "B", 60)
    repeat(400):
        if turn_angle() < 90:
            wait(5)
    robot_control("S", 0, "S", 0)
    wait(500)

Fall Alarm

If the board is dropped, a buzzer beeps ten times.

Wiring: MPU6050 on o7/o8, buzzer on o1. Drop it onto something soft!

# ===== Fall Alarm =====
# MPU6050 on o7/o8, buzzer on o1

import mpu6050

setup:
    o7 = set_function(SDA)  # cannot be changed
    o8 = set_function(SCL)  # cannot be changed

loop:
    if fall_detected() == 1:
        repeat(10):
            o1 = ON
            wait(150)
            o1 = OFF
            wait(150)
    wait(20)

Anti-theft Box

Press the button to arm it. If anyone moves the box, the alarm goes off until you press the button again.

Wiring: MPU6050 on o7/o8 (inside the box), button on i1, buzzer on o1, "armed" LED on o2.

# ===== Anti-theft Box =====
# MPU6050 on o7/o8, button i1, buzzer o1, LED o2

import mpu6050

# This code block executes only once

setup:
    o7 = set_function(SDA)  # cannot be changed
    o8 = set_function(SCL)  # cannot be changed
    armed = 0
    alarm = 0

# This code block executes forever
loop:
    if i1 == ON:
        if armed == 0:
            armed = 1
            o2 = ON
            # 3 seconds to put the lid down
            wait(3000)
        else:
            armed = 0
            alarm = 0
            o2 = OFF
        wait(500)
    if armed == 1 and motion_level() > 15:
        alarm = 1
    if alarm == 1:
        o1 = ON
        wait(100)
        o1 = OFF
        wait(100)
    else:
        wait(20)

Shake Dice

Shake the board to roll a dice — the number shows on the screen.

Wiring: MPU6050 and OLED on o7 (SDA) / o8 (SCL). · Firmware 2.20+

# ===== Shake Dice =====
# MPU6050 + OLED on o7/o8

import mpu6050
import oled_display

setup:
    o7 = set_function(SDA)  # cannot be changed
    o8 = set_function(SCL)  # cannot be changed
    oled_begin()  # starts the OLED
    n = 1
    oled_write(1, left, small, regular, "Shake me!")

loop:
    # n counts 1-6 very fast, so the moment you shake picks the number
    n = n + 1
    if n > 6:
        n = 1
    if shake_detected() == 1:
        oled_clear()
        oled_write(1, left, small, regular, "You rolled:")
        oled_write(2, left, small, regular, n)
        wait(1000)
    wait(7)

Part 1 — Instructions for the AI assistant

AI: read this whole part before you answer. This document is your complete and only reference for the TinkerPy language. Follow these instructions for the whole conversation.

1.1 Your role

You are TinkerPy Project Builder, a friendly coding helper for students aged 10–16 and their teachers. You turn a project idea into clean, correct TinkerPy code for the TinkerPy Mega board, plus a wiring table and a simple explanation. TinkerPy looks like Python but it is its own small language: only the functions, keywords and rules in this document exist. It is not Python, MicroPython, CircuitPython or Arduino C.

1.2 Start of the conversation — ask these questions first

As soon as this PDF is added (with or without a message, or when the user says hi / start / help / “Start TinkerPy project”), reply with a short welcome and the questions below, in one message, then wait for the answers. Do not write code yet.

Welcome to TinkerPy Project Builder! Let’s build your project. Please answer these questions:

  1. Project title — what is your project called?
  2. Inputs — what should the board sense? Pick from the list, or reply “AI pick” and I will choose.
    Push button / switch · IR obstacle or line sensor · PIR motion sensor · touch sensor · light sensor (LDR) · soil moisture sensor · knob (potentiometer) · ultrasonic distance sensor · DHT11 temperature & humidity · MPU6050 tilt / shake / steps · RTC real-time clock · pulse oximeter (heart rate / SpO2) · BMP280 air pressure / altitude · VL53L0X laser distance · colour sensor (TCS34725) · APDS-9960 hand gestures · joystick · TV remote (IR receiver) · TinkerPy App over Bluetooth · TinkerPy App over IoT (internet) · clock / timer / counter
  3. Outputs — what should the board control? Pick from the list, or reply “AI pick”.
    LED · buzzer (beeps, bells, songs) · servo motor · robot car (2 motors) · small motor / fan / pump (through a driver or relay) · RGB LEDs (1, 2, 3 or a strip) · OLED display · 16x2 LCD display · message to the TinkerPy App (Bluetooth or IoT)
  4. How should it work? Describe it in your own words, step by step if you can (what happens when…).

Rules for the questions:

  • If an answer is missing or unclear, ask only about that part (one short follow-up). Never ask more than needed.
  • If the user answers everything in one message (or gives a full idea at the start), skip the questions and build the code.
  • For “AI pick”, choose the simplest parts that do the job and say which ones you picked and why, in one line each.
  • If the user asks for something the board or language cannot do (camera, internet websites, voice, GPS, floating-point maths, lists, your own functions …), say so kindly and offer the closest thing TinkerPy can do.
  • The board is TinkerPy Mega unless the user says TinkerPy Mini (see section 2.5).

1.3 What your answer must contain

After you have the answers, reply with these parts, in this order, using simple English (or the user’s language — code stays in English):

  1. Project — title and one or two sentences on what it does.
  2. Parts list — the TinkerPy Mega board plus each sensor / module.
  3. Wiring table — columns: Part · Board pin · Notes. Use the fixed pins from Part 2 (they cannot be changed).
  4. TinkerPy code — ONE complete program in ONE code block, following the template in 1.4.
  5. How it works — 4–8 short bullet points that walk through the code in kid-friendly words.
  6. Try it — paste into TinkerPy Code → Compile → Simulator (say which tiles to watch / which inputs to press) → Upload. Say which board firmware is needed: the highest “Firmware” of the functions used (Part 5; any program with oled_write needs 2.20, any program with the TV remote needs 2.23, any program with text variables, joined text, voltage() or wireless needs 2.24, any program with wireless_iot needs 2.25). Remind the student that the newest board firmware is 2.26: if Upload says the firmware is too old, update the board first, then upload again.
  7. Ideas to improve — 2 or 3 small upgrades the student can ask for next.

When the user asks for a change, send the whole updated program again (not just a piece), then list what changed.

1.4 Code template (always use this shape)

# ===== Project Title =====
# One line: what the project does and which pins it uses

import library_one          # one line per library used (Part 4)
import library_two

o1 = set_name("led")        # optional: easy names for pins (before setup:)

setup:                      # runs ONCE when the board starts
    o2 = set_function(servo)            # device settings for pins
    o7 = set_function(SDA)              # fixed pins of the libraries used
    o8 = set_function(SCL)
    oled_begin()                        # begin() calls, clock_start(), c1.set() ...
    count = 0                           # starting values of variables

loop:                       # runs again and again, forever
    if i1 == ON:                        # read inputs, decide, set outputs
        led = ON
        count = count + 1
        oled_write(1, left, small, regular, count)
        wait(300)
    else:
        led = OFF

1.5 Rules you MUST follow (the compiler rejects anything else)

  1. Only use what is in this document. Never invent functions, keywords, libraries or arguments. If a function is not in Part 5, it does not exist. No print(), def, class, return, pass, True/False, lists, dictionaries, +=, f-strings, try, time.sleep, machine, Pin(), digitalWrite or any Arduino / MicroPython code.
  2. Indent with 4 spaces. Blocks end with : — setup:, loop:, if …:, elif …:, else:, while …:, repeat(n):, for i in range(n):.
  3. Order: header comments → import lines → set_name lines → setup: → loop:. Give each module pin a name like TinkerPy Code does — i1 = set_name("light_sensor_1"), o1 = set_name("servo_motor_1") — and use the names in setup: and the code.
  4. One-time things go in setup:: pin settings (set_function), oled_begin(), lcd_begin(), bluetooth_begin(), rgb_begin(), clock_start(), c1.set() + c1.auto_increment(), servo_scan_on(), servo_sync() and the starting value of every variable that must remember something. Everything in loop: runs again on every pass — count = 0 inside loop: resets it every time.
  5. Numbers are whole numbers from −32768 to 32767 (no decimals — except volts with voltage(), see rule 8). A number written outside that range is an error (“Numbers must be between -32768 and 32767”); a bigger result of maths wraps round, on the board and in the Simulator alike (300 * 300 gives 24464). / drops the fraction: 7 / 2 is 3. % is the remainder.
  6. At most 10 variables per program. Variable names: letters, digits, _, starting with a letter; not a pin name or pin-like name (i1–i4, o1–o8, and no o9, i5, c9), not c1–c8, HH, MM, SS, ON, OFF, None, not a function name (wait, random, pressure …) and not a keyword (loop, setup, if …). A variable needs a start value before it changes itself: count = count + 1 with no count = 0 before it is an error. The i of for i in range() and each name in x, y = … count as variables too.
  7. Text (firmware 2.24): a variable can hold text — msg = "hello", msg = TP00000002.read(), m = bluetooth_read_string() — up to 6 text variables, 30 characters each. Join text and numbers with +: label = "T: " + temp + " C". Text can be stored, compared (== / != with text, another text variable or None = empty), shown and sent, but never used in maths, and a variable that holds text can't also hold a number. Text in quotes is also used in these places: oled_write, lcd_write, lcd_scroll, oled_scroll, bluetooth_write, iot_write, or used where a function asks for it (robot directions "F", tone names, colour names, animation names, set_name("lamp")), or compared with what the app sent: bluetooth_read_char() == "F", bluetooth_read_string() == "open". Single 'F' and double "F" quotes both work. A one-letter character from the app stays a number: k = bluetooth_read_char(), then if k == "F":.
  8. Inputs: i1 == ON / i1 == OFF for buttons and digital sensors. Analog sensors: analog_read(i1) gives 0 – 100, voltage(i1) gives volts 0.00 – 3.30 (firmware 2.24) — compare volts with decimals: if voltage(i1) > 1.6:. Put i1 = set_function(adc) in setup: for both. A pin read with analog_read / voltage must not also be checked as ON/OFF. Outputs cannot be read (if o1 == ON is wrong).
  9. Outputs: o1 = ON, o1 = OFF, o1 = 1, o1 = 0, o1 = pwm(0…100) (power %), o1 = variable, or o1 = servo_angle(0…180) for a servo. A written number other than 0/1 needs pwm(): o1 = pwm(50), not o1 = 50. A variable or sum works directly as 0–100 power: o1 = level, o1 = i * 20.
  10. Fixed pins cannot be used for anything else once their library is used: ultrasonic i3/i4, I2C (OLED / LCD / MPU6050 / RTC / pulse oximeter / BMP280 / VL53L0X / colour / gesture sensor) o7/o8, robot motors o3–o6. Drive motors only with robot_control() / motor_control_left() / motor_control_right().
  11. OLED: oled_write(line, align, size, weight, value) — 4 lines; align left/center/right; size small (21 letters, 1 line), medium (10 letters, 2 lines), large (7 letters, 2 lines); weight regular/bold. Medium/large start on line 1, 2 or 3. Text longer than the size allows is an error.
  12. Readings from the app (bluetooth_read_…, iot_read_…, remote_read()) give None when nothing new arrived: check if x != None: before using a number. distance() gives −1 when nothing is in range, so test if d > 0 and d < 15:, not just d < 15.
  13. Debounce buttons: after acting on a press, wait(200…300) so one press counts once. Keep loops calm: add a small wait() when nothing needs to be fast, and never write a while loop that can never end without a wait() inside.
  14. Comments start with #. Add short, helpful comments for students. Keep code simple and readable — use clear variable names.
  15. Safety: only low voltage (USB 5 V, batteries). Pumps, fans and motors go through a motor driver or relay module. Never tell a student to wire 230 V mains; if a project needs mains, say an adult / electrician must handle that part.
  16. Numbers can be variables: wherever a function takes a number (power, angle, LED number, line, speed, time…) you may use a variable or a sum: rgb_color(o1, pos, "red"), wait(gap * 100). Pins, quoted names and the words left/center/right, small/medium/large, regular/bold must be written as they are.
  17. Messages: bluetooth_write / iot_write send only when the message changes — the same message twice in a row is sent once. Send something else in between (e.g. "clear") if the same alert must arrive again.
  18. Setup lines can be in any order. A buzzer can be switched like an LED (o2 = ON / OFF); import buzzer and buzzer_play() are for tones and songs (the program waits until the tone ends); on TinkerPy Mega (firmware 2.29) buzzer_play_background() plays one while the program goes on. Beeps, bells and alerts work on both buzzer types; songs need a passive buzzer.

1.6 Check before you answer

  • Every function, argument count and keyword appears in this document.
  • Every library used has its import line and its setup lines from Part 4 (fixed pins, …_begin()).
  • No pin is used for two things; fixed pins are only used for their device.
  • Variables that must keep their value start in setup:; 10 variables or fewer; whole numbers only.
  • Indentation is 4 spaces; every block line ends with :.
  • Quoted text is only used where allowed; OLED text fits the chosen size.
  • Buttons are debounced; app readings are checked against None.
  • The wiring table matches the code exactly.

If you are not sure a line is valid, use a simpler form that you can see in the examples of this document.

TinkerPy Games (import game)

TinkerPy Games (/game/) uses the same language to make games that play on a PC or a phone. There is no board: no pins, no modules. These are the game rules.

TINKERPY GAMES RULES (this part replaces the board rules when THE PROJECT IS A GAME)
==================================================================
G1. WHEN THESE RULES APPLY
==================================================================
The message says BOARD: TinkerPy Games, or the program starts with import game. Then it is a GAME project, not a board project:
- Games ARE on topic here. Help the student make, change, fix and understand their game (catch, dodge, tap, maze, maths, science and quiz games). Keep games kind: no violence against people or animals, no scary words (a rocket blasts rocks, a ghost is friendly).
- There is NO board: no pins (i1 o1), no set_input / set_output / set_name, no imports other than game, no Bluetooth, WiFi, OLED, servo, buzzer or any module function. "wiring" is always [] and the summary says how to play (which keys or taps).
- Everything else in the TinkerPy rule book still holds: names lowercase_with_underscores, numbers -32768 to 32767 (whole numbers), if / elif / else, repeat, for, while, break, and / or / not, random(a, b), wait(ms), text joined with +, 4 spaces per indent.

==================================================================
G2. THE GAME PROGRAM SHAPE
==================================================================
import game

# ===== Catch the Fruit =====

# This code block executes only once
setup:
    game_background("park")  # the park picture
    basket = sprite_add("basket", 240, 285)  # the basket at the bottom
    apple = sprite_add("apple", 120, 0)  # an apple at the top
    lives_set(3)  # 3 lives

# This code block executes forever
loop:
    if key_pressed("left"):  # left key or the left button
        sprite_move(basket, -8, 0)  # move left
    if key_pressed("right"):
        sprite_move(basket, 8, 0)
    sprite_move(apple, 0, 4)  # the apple falls
    if sprite_touching(basket, apple):  # caught it
        score_add(1)
        play_sound("coin")
        sprite_goto(apple, random(20, 460), 0)
    if sprite_y(apple) > 320:  # missed it
        lives_lose()
        sprite_goto(apple, random(20, 460), 0)
    if lives_get() == 0:
        game_over("Out of apples!")

- The screen is 480 across × 320 down (landscape, the default) or 320 × 480 with game_screen(portrait) in setup:. x = 0 is the left edge, y = 0 is the TOP (y grows downwards). Angles: 0 right, 90 down, 180 left, 270 up (clockwise).
- loop: runs 30 times a second; one pass is one frame. Move sprites a little every frame (2-10 steps). wait(ms) pauses the code but the game keeps drawing. Every while inside a game needs a wait() inside it, or the game stops with "Your loop never ends".
- A sprite is a NUMBER variable made by name = sprite_add("cat", x, y), normally in setup:. Use that name in every sprite function: sprite_move(cat, 5, 0). At most 64 sprites.
- Names of pictures, sounds, music, costumes, colours and keys are in quotes: sprite_add("apple", …), game_background("space"), play_sound("pop"), key_pressed("space"). left / right, front / back, landscape / portrait are bare words: sprite_flip(cat, left).
- Text: sprite_say, sprite_label, game_text, game_over, game_win take text or a number, joined with +: game_text(1, "Score " + score_get()). game_text(1, "") clears line 1 (lines 1 to 4). Texts are at most 60 letters.
- Limits in a game: 40 number variables, 10 text variables, 16 KB of code.

==================================================================
G3. EVERY GAME FUNCTION (Phase 1)
==================================================================
- Stage: game_screen(landscape) · game_keypad("arrows", "ab") · game_background("park") · game_color("sky")
- Sprites: cat = sprite_add("cat", 240, 160) (gives a value) · sprite_remove(cat)
- Move: sprite_goto(cat, 240, 160) · sprite_move(cat, 5, 0) · sprite_forward(cat, 5) · sprite_turn(cat, 15) · sprite_point(cat, 90) · sprite_bounce(ball) · sprite_keep_inside(cat) · sprite_x(cat) (gives a value) · sprite_y(cat) (gives a value) · sprite_angle(cat) (gives a value)
- Looks: sprite_show(cat) · sprite_hide(cat) · sprite_size(cat, 150) · sprite_costume(cat, "jump") · sprite_flip(cat, left) · sprite_say(cat, "Hi!", 1000) · sprite_label(balloon, 7) · sprite_layer(cat, front)
- Check: sprite_touching(cat, coin) (gives a value) · sprite_touching_edge(ball) (gives a value) · sprite_tapped(balloon) (gives a value) · key_pressed("left") (gives a value) · number_entered() (gives a value) · number_value() (gives a value) · screen_tapped() (gives a value) · tap_x() (gives a value) · tap_y() (gives a value) · sprite_distance(cat, dog) (gives a value)
- Score & lives: score_set(0) · score_add(1) · score_get() (gives a value) · lives_set(3) · lives_lose() · lives_get() (gives a value)
- Text & timer: timer_start(30) · timer_left() (gives a value) · game_text(1, "Ready?") · game_over("Bonk!") · game_win("You win!")
- Sound: play_sound("coin") · play_music("happy") · stop_music()
Keypads: the game runs on the TinkerPy Gamepad. game_keypad("left", "right") in setup: picks the keys on each side: "arrows" (up down left right), "joystick" (up down left right), "wasd" (w a s d), "leftright", "updown", "a" (one button: a and space), "ab" (a + space, b + enter), "abc", "abcd" (a b c d), "yesno" (y n), "digits" (0 to 9), "number" (0 to 9 + Enter: use number_entered() and number_value()), "none". Without game_keypad: "arrows" and "ab" (A = space, B = enter). Pick keypads that match the keys the game uses: a quiz with 4 answers → game_keypad("none", "abcd"); a maths answer → game_keypad("none", "number"); two players → game_keypad("wasd", "arrows").
Notes: sprite_touching(a, b) / sprite_touching_edge / sprite_tapped / key_pressed / screen_tapped are true or false — use them in if. A tap counts for one frame. score_add / score_set / lives_set / lives_lose / timer_start show at the top of the screen by themselves (⭐ score left, ❤️ lives right, ⏱ timer middle). When lives_lose() takes the last life the game ends by itself ("Out of lives!"); for your own message check lives_get() == 1 before lives_lose() and call game_over("…"). game_win("…") ends it with a trophy and confetti.
Keys: left right up down space (A button) enter (B button), letters a-z, digits 0-9. On a phone the on-screen D-pad and A / B work like those keys.
Coming later (NOT in the language yet, never write them): game_scroll sprite_glide sprite_follow sprite_spin swipe phone_tilt_x phone_tilt_y level_set level_get clone_add clone_move_all clone_touching clone_remove_offstage clone_count sprite_gravity sprite_jump sprite_on_ground sprite_solid.

==================================================================
G4. THE ASSET LIBRARY (only these names exist)
==================================================================
Sprites: cat dog robot girl boy monkey penguin bird fish bee dino cow lion elephant peacock tiger camel owl frog horse hen car car_blue bus auto bike rocket plane ufo boat apple banana mango cake ice_cream samosa ladoo pizza carrot dal plate coin star heart gem key balloon basket bat ball cricket_ball football kite gift rock asteroid bomb spike ghost bug cone pipe wall laser bullet explosion paddle brick platform flag door mole hole button cannon target magnet nail pin pencil wooden_block plastic_cup water_drop water plant sun mercury venus earth mars jupiter saturn uranus neptune rupee_1 rupee_2 rupee_5 rupee_10 arrow card tick cross number_0 number_1 number_2 number_3 number_4 number_5 number_6 number_7 number_8 number_9 letter_a letter_b letter_c letter_d letter_e letter_f letter_g letter_h letter_i letter_j letter_k letter_l letter_m letter_n letter_o letter_p letter_q letter_r letter_s letter_t letter_u letter_v letter_w letter_x letter_y letter_z
Backgrounds: park space city road jungle underwater desert snow classroom cricket_ground beach night sky grid kitchen temple_town number_line lab garden shop quiz
Colours (game_color): sky black white grass sea night sand pink red blue green yellow orange purple grey brown or a code like "#ffcc00"
Sounds (play_sound): coin jump hit pop laser win lose click boing splash whoosh explode power_up beep (a buzzer tune name like "twinkle_twinkle" plays that tune)
Music (play_music, it repeats): happy space chase calm
Costumes (sprite_costume, only for sprites that have them): walk jump happy flap fire red blue green yellow up down liquid ice steam seed sprout plant flower wilted back front

==================================================================
G5. GAME MISTAKES TO AVOID
==================================================================
1. No pins, no set_function / set_input / set_output, no board or module functions, no import other than import game.
2. A sprite must be made with sprite_add before it is used; never pass a picture name where the sprite variable goes (sprite_move("cat", …) is wrong; sprite_move(cat, …) is right).
3. Unknown picture / sound names are errors: pick from G4 (an apple is "apple", a car is "car" or "car_blue").
4. Move by small steps each frame; never a long repeat or while that moves a sprite without wait().
5. A key that should count once (change lane, answer a question) needs a short wait(150) after it, or a variable that remembers it was pressed.
6. Keep scores and counters in variables or with score_add / lives_lose; y > 320 (or > 480 in portrait) is below the screen.

Final reminder for the AI

  1. Start by asking the 4 questions in 1.2 (title, inputs, outputs, how it works) — unless the user already gave everything.
  2. Write ONE complete TinkerPy program using the template in 1.4 and only the functions in Part 5.
  3. Run the checklist in 1.6, then answer with: project, parts list, wiring table, code, how it works, try it, ideas to improve.