๐ฅ From Arduino to Mars: Why You Should Be Using TinyGo for Embedded Web Development
If youโve ever attempted to build something that lives at the intersection of embedded systems and the modern web โ say, a microcontroller that serves a WASM-powered control dashboard over HTTP โ youโve probably run into some harsh realities:
- C is painful.
- Rust is powerful, but finding embedded libraries that just work is a chore.
- JavaScript, while king of the browser, isnโt welcome on your $2 MCU.
Is there a better way? What if you could use Go, a modern compiled systems language with safe memory handling and a thriving toolset, to build for microcontrollers AND compile to WebAssembly (WASM)?
Let me introduce you to TinyGo โ the smallest, fiercest, and most fun way to build projects that live somewhere between the clouds and your breadboard.
๐ What is TinyGo?
TinyGo is a Go compiler for small places โ literally. It allows you to run Go programs on microcontrollers like the Arduino Nano 33, Raspberry Pi Pico, or even run WASM blobs in no_std environments.
Key features:
- โจ Drop-in Go syntax (not all of it, but enough)
- ๐ฆ Cross-compilation to many MCUs (AVR, ARM Cortex-M0+, RISCV)
- ๐ธ Compiles to WASM โ and the output is small (weโre talking kilobytes)
- ๐ฅ Integrates with Visual Studio Code and common Go tooling
๐งช The Experiment: Live Dashboard + Sensor on the Same Microcontroller
Let me show you a crazy-cool idea: what if a single microcontroller could both read sensor data and serve a WASM web UI to visualize it in real time?
Imagine a soil moisture sensor that hosts its own dashboard. No Raspberry Pi. No external web server. Just one board.
We'll build:
-
A TinyGo app that:
- Reads values from a DHT11 sensor (humidity + temperature)
- Hosts a tiny HTTP server when connected via USB serial or WiFi (ESP32 anyone?)
- Serves a WASM + HTML dashboard built from the same Go source
A frontend dashboard written using syscall/js in Go and compiled to WASM
๐ฆ Setting Up TinyGo
brew tap tinygo-org/tools
brew install tinygo
# OR install via Go:
go install github.com/tinygo-org/tinygo@latest
To target a device:
tinygo flash -target=arduino-nano33 path/to/main.go
To target WASM:
tinygo build -o static/main.wasm -target=wasm ./wasm-ui
๐ Reading the Sensor (main.go)
package main
import (
"machine"
"time"
"fmt"
)
func main() {
sensor := machine.D2 // digital pin 2
sensor.Configure(machine.PinConfig{Mode: machine.PinInput})
for {
reading := sensor.Get() // fake reading; insert actual DHT11 logic here
fmt.Printf("Sensor reading: %t\n", reading)
time.Sleep(time.Second * 2)
}
}
Weโre keeping it simple, but you can connect I2C or SPI sensors and use libraries like tinygo-org/drivers.
๐ Serving the WASM UI from the MCU
Using a minimal HTTP server (WiFi or serial-over-USB):
import (
"net/http"
"embed"
)
//go:embed static/*
var static embed.FS
func main() {
http.Handle("/", http.FileServer(http.FS(static)))
http.ListenAndServe(":8080", nil)
}
Note: This is pseudo-code. Not all boards support Go's net/http. For truly tiny devices, youโd embed the HTTP binary with a lightweight TCP server or make the browser request data over serial.
๐ฅ Building the WASM Dashboard
Structure:
wasm-ui/
โโโ main.go
โโโ index.html
main.go (WASM)
package main
import (
"syscall/js"
)
func renderData(this js.Value, args []js.Value) interface{} {
document := js.Global().Get("document")
div := document.Call("getElementById", "sensor")
div.Set("innerText", "Temperature: 24ยฐC\nHumidity: 60%")
return nil
}
func main() {
js.Global().Set("renderData", js.FuncOf(renderData))
// Call once on load
renderData(js.Null(), nil)
// Keep it alive
select {}
}
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="wasm_exec.js"></script>
</head>
<body>
<h1>๐ Sensor Dashboard</h1>
<div id="sensor"></div>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
go.run(result.instance);
window.renderData();
});
</script>
</body>
</html>
๐ง Why This Is A Game Changer
- Traditionally, embedded devices are data slaves โ sending sensor data elsewhere for visualization.
- But with TinyGo + WASM, your device owns the whole stack.
- This pattern is incredibly useful for remote sensors, pop-up local networks, event-driven instruments, and hackathon hardware!
๐งฑ Real World Uses
- ๐ Off-grid weather stations that host their own progressive web apps
- ๐ซ Classroom science kits that broadcast dashboards over local WiFi
- ๐จโ๐ Remote devices serving diagnostics in space or on edge networks
- ๐ก Smart IoT devices with no back-end reliance
๐ง Gotchas & Caveats
- TinyGo still doesnโt support Go 1.22 fully โ check compatibility
- Performance is great on fast boards, shaky on tiny AVR 8-bit ones
- syscall/js is verbose, but Goโs generics and structs donโt yet work fully in WASM mode
๐ฎ Conclusion
TinyGo is a secret weapon for developers who dream of merging hardware and the web with one elegant system. Programming microcontrollers used to require learning archaic C, vendor-specific SDKs, and crossing your fingers on every flash.
But now? You get modern tooling, great readability, and the power of Go in the smallest places โ or even straight into your browser.
So try it. Grab a $4 board, install TinyGo, and go build your next project that lives between copper and cloud โ๏ธโก.
๐ Resources
- Official: https://tinygo.org
- Sensor drivers: https://github.com/tinygo-org/drivers
- Great starter repo: https://github.com/aykevl/tinygo-wasm-experiments
๐ ๏ธ If you're looking to prototype hardware + web apps fast and smart โ we offer just the kind of embedded fullstack help you need.
Top comments (0)