Turn a Raspberry Pi into an IoT gateway — no firmware, no code

By Synacl · 9 min read · Published

A Raspberry Pi on a shelf is already most of an IoT gateway: it has Ethernet or Wi-Fi, it sits on the same network as your meters and smart plugs, and it never sleeps. What it lacks is the software that turns readings into a dashboard you can open from anywhere. This guide adds that with one command — no firmware to flash, no script to write — using synacl-gateway, the open-source reference gateway for Synacl. By the end the Pi reports its own CPU temperature to a chart, relays a Tasmota plug's power reading from your local MQTT broker, polls a Modbus TCP meter, and keeps recording while the Wi-Fi is down.

What a gateway is, here

A gateway sits between equipment and a platform: it keeps one connection to the cloud, receives the list of devices it should read, reads each on its interval, and publishes the readings. On Synacl the usual gateway is an ESP32 running the Synacl firmware; synacl-gateway is the same role in Node.js, speaking the same public protocol, so a Pi shows up in the app as an ESP32 would. In 0.1.0 it reads the machine it runs on (Host metrics), subscribes to a broker you already have (Local MQTT bridge), and polls Modbus TCP devices on the LAN.

What you need

Step 1 — Install Node.js

synacl-gateway needs Node.js 20.11 or newer; 22 LTS is recommended. Which package depends on your Pi OS release:

node -v should now print 20.11 or higher.

Step 2 — Register a software gateway

In the Synacl app open Gateways → Add gateway and choose Software gateway. Give it a name — Workshop Pi — and save; leave the gateway ID blank to get one of the form gw_…. The gateway appears as offline, and its Connection Info shows the broker address, a username, a password, and a line labelled Quick start (Node.js). Everything the Pi needs is in that line; the software gateway article explains each field.

Step 3 — The one line

Paste the Quick start line into a terminal on the Pi. With your own ids it looks like this:

npx -y synacl-gateway@latest init --broker mqtts://mqtt.synacl.com:8883 --tenant <account id> --gateway <gw_…> --user <username> --pass <password> && npx -y synacl-gateway@latest run

init writes the settings to ~/.synacl-gateway/config.json, readable by your user only, then proves the credentials against the broker — a wrong password or a mistyped id fails here, with a message that says which. run starts the gateway in the foreground, and within seconds the gateway card in the app turns online. Ctrl-C stops it. The line carries the gateway's password: start it with a space so your shell keeps it out of its history.

Step 4 — Make it a service

To have the gateway start at boot and restart if it crashes, install it globally and register a systemd unit:

sudo npm i -g synacl-gateway
synacl-gateway init --broker mqtts://mqtt.synacl.com:8883 --tenant <account id> --gateway <gw_…> --user <username> --pass <password>
sudo synacl-gateway service install

init takes the same flags as before; run it as the user the service should run as, since the unit reads that user's ~/.synacl-gateway. journalctl -u synacl-gateway -f follows the log, and synacl-gateway status reports connection, config sync, buffer and devices, even when the gateway is stopped. Without sudo, service install --user writes a per-user unit. There is a Docker image too (ghcr.io/synacl-iot/synacl-gateway, arm64 and amd64); the software gateway article has its two commands.

Step 5 — Monitor the Pi itself (cpu.temp)

With the gateway online, open Devices → Add device. The protocol list now has a Software gateway group — it appears only after the gateway has connected and reported which protocols it supports, which is why the gateway comes first. Choose Host metrics, pick Workshop Pi, set a sample interval of 60,000 ms, and add tags:

Tag name Metric
cpu_temp cpu.temp
cpu_load cpu.load
mem_used mem.used_pct
disk_used disk.used_pct

Save. There is no resend config step for a software gateway: the new device list is pushed to the Pi immediately, and the first reading arrives within a minute. cpu.temp on a Pi is the SoC temperature — what vcgencmd measure_temp prints, minus the SSH session. There are eight metrics in all: these four plus load.1m, uptime_s, net.rx_bps and net.tx_bps, described in the host metrics article.

One property to know before you put a rule on any of them: a metric the machine cannot provide is left out of the reading, never sent as 0. On a VM with no temperature sensor the cpu_temp chart stays empty rather than drawing a flat line at zero that looks like a reading; synacl-gateway metrics prints what a machine can and cannot provide, and why.

Now put it on a dashboard: Dashboards → New dashboard, open the Add Widget drawer's From device tags tab and click cpu_temp — it lands as a ready-configured readout — then add a line chart bound to the same tag. Open the dashboard on your phone, compile something on the Pi, and watch the number climb. The first dashboard article covers the widgets.

Step 6 — Bridge a Tasmota plug from your local broker

Readings on a local broker — Tasmota and Shelly plugs, zigbee2mqtt, Home Assistant — are stuck on the LAN. The bridge driver subscribes to that broker and forwards one value per tag to Synacl. Nothing changes on the local side, and the broker is never exposed to the internet: the Pi connects out to both.

Add a device with protocol Local MQTT bridge, gateway Workshop Pi. Enter the local broker URL as the Pi sees it — mqtt://192.168.1.20:1883 — and the broker's username and password if it has them. A Tasmota plug with the MQTT topic plug1 publishes its telemetry every 300 s to tele/plug1/SENSOR as JSON, and its relay state to stat/plug1/POWER as a bare ON or OFF:

Tag name Topic JSON path
power_w tele/plug1/SENSOR ENERGY.Power
voltage tele/plug1/SENSOR ENERGY.Voltage
relay stat/plug1/POWER (empty)

The path is dot notation, and a numeric segment indexes an array (sensors.0.temp). Values are normalised so they chart and compare: ON/OFF and true/false become 1/0, numeric strings become numbers, other strings are kept. The gateway keeps the latest value received per tag and publishes it at the device's sample interval, so a chatty device is neither throttled nor suspended; if nothing arrived for a tag, nothing is sent. A zigbee2mqtt sensor is the same recipe with topic zigbee2mqtt/<friendly name> and path temperature.

The device goes unreachable with the reason bridge/no_message after three sample intervals with nothing — never sooner than 300 s, so a Tasmota plug on its default telemetry period does not flap — and reports bridge/disconnected if the local broker is gone for more than ten seconds. The bridge is one-way in 0.1: it reads from your broker and does not publish to it, so switching the plug from Synacl is not part of this release. The bridge article has the Home Assistant recipe and the rest.

Step 7 — Read a Modbus TCP meter

Add a device with protocol Modbus TCP and choose Workshop Pi as the gateway. It is the same form that serves an ESP32, with the same fields: the device's IP, port (502) and unit ID, and per tag a register type (holding, input, coil, discrete), an address, a format (u16, s16, u32, s32, f32) and, for 32-bit formats, a word order. For an Eastron SDM630, phase 1 voltage is input register 0 as f32, big word order. The Modbus TCP article has the field-by-field version, and How to read a Modbus energy meter explains addresses, floats and word order for when the datasheet is unclear.

Failures are named on the device page, which saves an afternoon: TCP connect failed to 192.168.1.50:8883 (ECONNREFUSED) means the port is wrong (that one is the platform's MQTT port, a common copy-paste), modbus/timeout means the device took the connection and did not answer, and modbus exception 2 (illegal data address) means the register is not where you think. A ping proves none of these; nc -vz <ip> 502 from the Pi tests the port itself. Writes are supported too: a single coil or holding register, the same write the ESP32 accepts.

What happens when the Wi-Fi drops

Sooner or later the Pi's uplink goes away while the meters keep running. The gateway keeps reading. Every reading taken while the connection is down is appended to a buffer on the SD card — 64 MiB or seven days by default, whichever comes first — and when the connection returns it is replayed on a separate backfill topic in paced batches, oldest first. Replayed readings go into history, so the charts fill in; they do not re-fire rules or move the device's live value, which is right for a reading that is an hour old. They are on disk before they are counted, so a crash or a reboot loses nothing.

Store-and-forward is enabled per account; the offline buffering article has the details. The gateway also evaluates each tag's alert threshold locally, like the ESP32, so the moment a value leaves its range is recorded on the Pi even while the cloud is unreachable.

Alarms

Two mechanisms, for two needs. A threshold on a tag gives a yellow dot on the device and a recorded event when the reading leaves its range and again when it returns — set threshold start and end on cpu_temp to 0 and 70, and a Pi in a hot enclosure tells you so; that comparison happens on the gateway. For a message, create a rule: Rules → New rule, a reading crosses a threshold, Workshop Pi → cpu_temp greater than 70, an e-mail or webhook action, and a cooldown so a temperature hovering at the limit sends one alert rather than a hundred. Alert thresholds and create a rule have the options; for the Pi itself, a rule can fire on its offline event.

What this does not do

synacl-gateway 0.1.0 has no GPIO, I²C, 1-Wire or serial drivers: a DS18B20 on the Pi's header is not read by it. For pins and buses the ESP32 firmware is the tool, flashed from the browser; both kinds of gateway sit side by side in one account. Nothing here is a safety function — a Modbus write through the Pi is a network message, and an unplugged Pi cannot send one; anything that can hurt someone stays behind a physical interlock.

Everything the Pi says and hears is on the protocol page, with a JSON Schema per message, and the source is Apache-2.0 at github.com/synacl-iot/synacl-gateway. If your machine is not a Pi, nothing above changes: the same package runs on a NUC, a server, or a container next to your SCADA.

Try it on your own hardware

Synacl is free for five devices — no card, no sales call. Flash a gateway from the browser, add your first device, and see live data in a few minutes.