The DeviceScript console is the channel through which we observe what happens inside the program, both in the simulator and on a connected board.
In Arduino, our window to the world is Serial.print(). It works, but it’s primitive. We have to concatenate strings, convert numbers to text manually, and if we want to see the state of a complex object, we have to print its variables one by one.
In DeviceScript, we have an advantage. Being in the VS Code and TypeScript ecosystem gives us “real” debugging tools.
The console object
In DeviceScript, debugging is primarily done through the global console object, with an API similar to JavaScript in other environments.
The output of these commands travels from the microcontroller (or the simulator) via USB cable or WiFi, and is displayed directly in the “DeviceScript” panel of the VS Code terminal.
Log levels
Not everything is a simple message. We have several severity levels that help us visually filter the noise:
console.log("Standard message: Everything is fine")
console.debug("Debug: Boring but useful internal data")
console.warn("Warning: Something strange happened, but I'm still working")
console.error("Error: Houston, we have a problem!")Using console.error does not stop the program, but in VS Code it usually highlights the line in bright red, which helps a lot to quickly detect failures amidst a sea of text.
Formatting strings
In C++ (Arduino), making a sentence with variables is often tedious:
Serial.print("Temperature: "); Serial.print(t); Serial.println(" C");
In DeviceScript, we use TypeScript’s Template Strings (backticks “). It’s a marvel for readability:
let temperature = 24.5
let humidity = 60
// Clean, elegant, and readable
console.log(`Current reading -> Temp: ${temperature}°C | Humidity: ${humidity}%`)Logging structured data
We can pass multiple values to console.log, although for logging sensor measurements DeviceScript incorporates a more specific option: console.data automatically adds a timestamp and sends the data to the DeviceScript - Data panel.
const robotState = {
id: "Robot-01",
battery: 85,
position: { x: 10, y: 20 },
active: true
}
console.log(robotState)
console.data({ battery: robotState.battery, x: robotState.position.x })The exact format of a complex object may depend on the runtime version. For telemetry, it is preferable to send a flat object with console.data.
This is vital when we work with sensors that return a lot of data or complex configurations. Being able to see the complete state of an object at a glance saves hours of debugging.
Inspecting the program with the debugger
Sometimes, console.log is too fast and fills the screen (“blind scrolling”). If we have a sensor reading every 50ms, the console becomes unreadable.
DeviceScript and VS Code have a great feature: Watch Variables.
Since we are in a real debugging environment, we can set Breakpoints.
- Click on the left margin of a line of code to add a breakpoint.
- Run the program in Debug mode with
F5or from the debug panel.
When the code reaches that line, the microcontroller will pause.
In the Variables panel, you can check the state of the program at that instant, inspect objects, and review collections.
When you pause the program, the service communication layer continues processing packets, but your DeviceScript code stops advancing. Do not debug equipment this way if its state could become dangerous when the control logic is halted.
Using the visual panel
In addition to the console, the dashboard allows you to observe the state of the simulated services.
If we use standard services like LightBulb or Button, we don’t need to fill the code with redundant messages.
Simply look at the Dashboard.
- Does the button icon depress? -> The code detects it.
- Does the light bulb icon turn on? -> The output logic works.
This seems obvious, but we often fill the code with unnecessary logs when a simple glance at the service’s state in the panel would give us the answer.