Scripts Without Reflashing
You flashed the firmware once in Getting Started. In this guide you never touch the USB cable again: you write two different scripts, test each one in the browser, and push each one to the board over the air. Then you power-cycle the board and watch the last script come back on its own. About 10 minutes.
What You'll Build
A blinking LED, built from blocks and tested in the Emulator before it reaches the board.
A press counter that replaces the blink with one click and reports through
print, introducing the logs you will debug with from now on.Proof that a persistent script survives a power cycle.
This is the everyday loop of the platform: the board is generic, the behavior is a script, and changing it costs seconds instead of a compile-upload cycle. Read more in Edge Logic Deployment.
Prerequisites
The board from Getting Started, online and authorized under your account.
Nothing else. The firmware from Getting Started already exposes the onboard LED as digital output
0and the BOOT/FLASH button as button0, and this guide does not change it.
Step 1: Blink, from the Emulator to the Board
Build the Script
Open the Sandbox page and create a new script; call it Blink.
The script keeps one variable, state, flips it every half second, and writes it to the LED. In the Visual Editor, assemble the blocks shown below. Press Compile to turn the blocks into the UniotLisp code on the second tab; that code is what actually runs on the device.
What the script does:
Initial value — the set state to false block outside the task runs once, when the script starts. The compiler turns every variable into a
definethat creates it as(), followed by asetqwith the block's value;()is how UniotLisp writesfalse, so here both lines set the same thing.Main loop — run task times 0 ms 500 is the program's entry point: everything in its do slot runs every 500 ms, and
0times means forever. In code it is(task 0 500 '...), and theprogninside it just means "run these in order". See the task-based execution model.Toggle — set state to not state reads the variable, flips it with the not block, and stores it back. The not block compiles to
(not (bool state)):boolfirst turns whatever is in the variable into true or false, so not works even when the variable holds a number.Output — digital write state to pin 0 sends the value to digital output
0, which the firmware mapped to the onboard LED:(dwrite 0 state). The0is a register index, not a GPIO number; see The Register System.User library block — the comment block at the top of the code declares which primitives the script uses. The Visual Editor writes it from the blocks you placed; there is nothing to add for it.
Run It in the Emulator
The Emulator runs your script in the browser on the same interpreter a device uses, with an interactive card standing in for each primitive.
Select your device in the sidebar. The Emulator then uses the device's registers and warns you if the script asks for something the device does not have.
Press the play button, or Ctrl+Enter (Cmd+Enter on Mac).
A floating window opens with cards, included Digital Write. Its LED blinks every half second.
Deploy
Press Deploy in the Emulator's header. The script is sent to the device and the window closes.
Step 2: Count Button Presses
The second script reacts to input and talks back. Create a script called Counter. Every press of the button adds one to a counter; the LED is lit while the count is even, and the count is printed after each press.
What the script does:
Initial value — set count to 0 outside the task runs once at start. As before it becomes a
defineand asetq:(define count ())creates the variable,(setq count 0)gives it its number.Main loop — run task times 0 ms 50 polls twenty times a second, forever:
(task 0 50 '...). Fast enough that a click is never missed, slow enough to leave the device idle most of the time.Button check — the if block's condition is is button 0 clicked, which is true exactly once per press-and-release and then clears itself, so the do slot runs once per click no matter how long the button is held. Compiled:
(if (bclicked 0) (progn ...)), withprognagain grouping the blocks inside the do slot.Counter — change count by 1 adds one to the variable:
(setq count (+ count 1)). The change block is a shortcut for "set to itself plus a number".Output — digital write takes a comparison as its value: remainder of count ÷ 2 = 0, true while the count is even. The
=in the comparison block compiles toeql, so the code reads(dwrite 0 (eql (% count 2) 0)). The LED turns off on the first press and on again on the second.Report — the print count block sends the value out of the script as a log line:
(print count). Where it lands depends on where the script runs, which is the point of the next section.
Read the Logs
Compile and run with the device selected. The Emulator now shows a Button Clicked card next to the Digital Write card. Click the button a few times: the LED card toggles, and the Logs panel on the right prints a timestamped line with the count after each click. If the panel is hidden, press Logs in the header. To follow the order of calls, turn on Debug (the bug icon in the header): each primitive call lights up its card and the run pauses 300 ms after every call.
There are two different logs, and it helps to know which is which:
The Emulator's Logs panel shows what the script says: every
print, plus any error with its full message. See Logs.The Logger pane in the Sandbox shows what the script asks for: the compiler's output and a trace of primitive calls and their answers. See Logger.
Press Deploy, then press BOOT/FLASH on the board. Open your device's page and switch to the Logs tab: the same count lines appear there, delivered over MQTT. Errors from a deployed script arrive in the same place, which makes print your main tool for debugging scripts on hardware.
Step 3: Survive a Reboot
A deployed script can be volatile or persistent (by default). A volatile script runs until the device restarts. A persistent script is saved to the device's flash, verified by checksum, and started again on every boot; if it ever fails to load, the device still boots normally. See Script Persistence.
Unplug the board and plug it back in. The status LED blinks while the device reconnects and goes dark once it is online. Press BOOT/FLASH: the LED toggles and a new line appears in the Logs tab. Nobody deployed anything; the device restored the script itself. The count starts from zero, because variables live in memory, not in flash.
Troubleshooting
The play button is disabled. The Sandbox shows Recompile required after any edit. Press Compile first; if the Emulator is still running from before, stop it, since Compile waits for the run to end.
Compile fails with "Undefined symbol". This happens with hand-written code when a primitive is missing from the user library block at the top of the script. Add a defjs line for it; the Visual Editor adds these automatically. See User Library Block.
A card shows a warning triangle. Hover it. "Registers are out of bounds" means the script uses an index the selected device never registered; compare with the device's Registers tab. "Unavailable in the selected device" means the device's firmware does not provide that primitive at all.
The Emulator run stops on its own. A task set to run forever stops after 9,999 iterations in the Emulator only; the window title changes to Finished. On the device it keeps running.
Deployed, but the board does nothing. Check the device is Online on the Devices page, then the Script tab on the device page to confirm the deployment, then the Logs tab for an error message. See Debugging Scripts.
The LED seems inverted. On ESP8266 boards the onboard LED is active LOW, so "on" is dark; see the hint under Prerequisites. If the LED instead blinks steadily on its own and ignores the script, the device lost WiFi and Uniot Core has taken the LED back to show the connection status until it reconnects.
The script did not come back after a reboot. It was deployed as volatile. Deploy again and pick the persistent option.
What's Next
Dim an LED from a SliderScriptingEmulatorVisual EditorLast updated