This repository implements an IoT system for controlling relay modules from an Android app via MQTT.
The system has two MQTT access paths:
- Private (required for devices): MQTT over WireGuard on
1883(no TLS, tunnel provides transport security). - Public (for Android without WireGuard): MQTT over TLS on
8883(encrypted, certificate-based server identity, optional client certs).
The system consists of three main components:
- Android App – UI to discover devices and toggle relays (MQTT over TLS
8883). - Raspberry Pi Pico W – relay controller node (Wi-Fi uplink + WireGuard client + MQTT to
1883). - Raspberry Pi 5 (Provider) – WireGuard server, Mosquitto MQTT broker (both
1883and8883), and discovery/provider daemon.
- Pico W devices connect to the local network via Wi‑Fi.
- The Raspberry Pi 5 must be in the same Wi‑Fi/LAN segment because device discovery uses UDP broadcast (local network only).
- Over that uplink, Pico W devices establish a WireGuard tunnel to the Pi 5 (
10.8.0.0/24). - Pico W devices publish/subscribe MQTT via
10.8.0.1:1883(inside WireGuard).
- The Android app connects to Mosquitto via MQTT over TLS on
8883. - This allows Android to work from outside the home network without requiring WireGuard.
1883is used by Pico W nodes via WireGuard (and optionally by other trusted hosts on LAN).1883must NOT be exposed to the public Internet.- Restrict it to:
- WireGuard subnet (
10.8.0.0/24) and/or - local LAN subnet(s)
- WireGuard subnet (
8883is exposed for Android clients that do not run WireGuard.- Traffic is encrypted with TLS.
- Authentication should include:
- MQTT username/password, and optionally
- client certificates (mTLS) if you want per-device certificate control.
- Written in Java (with some Kotlin UI utilities).
- Uses Eclipse Paho MQTT client.
- Dynamically builds device list based on
AQUA_DEVICES_UPDATE. - Subscribes to per-device topics for state updates.
- Supports relay toggling and time-based schedules.
- Firmware: C++ (Arduino).
- JSON parsing:
cJSON(included). - Key features:
- Wi‑Fi uplink (Earlephilhower RP2040 core)
- WireGuard client using
arduino-wireguard-pico-w - MQTT subscribe/publish (
PubSubClient) to10.8.0.1:1883 - NTP time sync (optional but recommended for schedules)
- state machine
- OLED display (
Adafruit_SSD1306) - EEPROM persistence
- hardware watchdog
- discovery responder (UDP)
- OTA updates (
ArduinoOTA) (optional)
WireGuard library (Pico W): https://github.com/jaszczurtd/arduino-wireguard-pico-w
- Written in C and runs as a
systemdservice. - Periodically:
- broadcasts UDP discovery
- receives UDP responses from Pico W
- verifies availability of Pico W devices
- publishes device list to
AQUA_DEVICES_UPDATE
| Topic | Direction | Payload Example | Purpose |
|---|---|---|---|
AQUA_DEVICES_UPDATE |
Provider → App | {"devices":[...]} |
Broadcasts device list |
AQUA_DEVICE_SWITCH_SET/{hostname} |
App → Pico W | {"isOn1": true} |
Relay toggle |
AQUA_DEVICE_TIME_SET/{hostname} |
App → Pico W | {"dateHourStart": 300, "dateHourEnd": 600} |
Schedule relays |
AQUA_DEVICE_STATUS/{hostname} |
Pico W → App | {"status":"ok",...} |
Reports full device state |
Pico W nodes must be on the same local LAN/Wi‑Fi segment as the Pi 5 because discovery uses UDP broadcast.
| Port | Protocol | Purpose | Required |
|---|---|---|---|
| 51820 | UDP | WireGuard server endpoint (Pico W → Pi 5) | ✅ yes |
| 1883 | TCP | MQTT for Pico W / internal clients (WireGuard/LAN only) | ✅ yes* |
| 8883 | TCP | MQTT over TLS for Android clients (public) | ✅ yes |
| 8266 | TCP | OTA firmware updates (optional) | |
| 12345 | UDP | Device discovery via broadcast (LAN only) | ✅ yes |
* Security requirement: 1883 must be reachable only from WireGuard and/or LAN. Do not expose it publicly.
Replace LAN_SUBNET with your local network CIDR (e.g. 192.168.2.0/24).
# WireGuard server
sudo iptables -A INPUT -p udp --dport 51820 -j ACCEPT
# MQTT over TLS (public for Android)
sudo iptables -A INPUT -p tcp --dport 8883 -j ACCEPT
# MQTT plaintext (internal only)
sudo iptables -A INPUT -p tcp --dport 1883 -s 10.8.0.0/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 1883 -s LAN_SUBNET -j ACCEPT
# (Optional) OTA firmware updates
sudo iptables -A INPUT -p tcp --dport 8266 -j ACCEPT
# UDP discovery (LAN only)
sudo iptables -A INPUT -p udp --dport 12345 -s LAN_SUBNET -j ACCEPT
# Save firewall rules
sudo netfilter-persistent savesudo apt update
sudo apt install -y mosquitto mosquitto-clients libmosquitto-dev libcjson-dev
sudo systemctl enable mosquitto
sudo systemctl start mosquittosudo mosquitto_passwd -c /etc/mosquitto/passwd your_usernameBind 1883 to WireGuard (and optionally LAN), and keep it off the public Internet.
Example /etc/mosquitto/conf.d/internal.conf:
# WireGuard-only listener (recommended)
listener 1883 10.8.0.1
allow_anonymous false
password_file /etc/mosquitto/passwd
# (Optional) LAN listener if you have trusted LAN clients:
# listener 1883 192.168.X.Y
# allow_anonymous false
# password_file /etc/mosquitto/passwdExample /etc/mosquitto/conf.d/tls.conf:
listener 8883
protocol mqtt
allow_anonymous false
password_file /etc/mosquitto/passwd
# Server TLS (required)
cafile /etc/ssl/certs/ca-certificates.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
# Optional: require client certificates (mTLS)
# require_certificate true
# use_identity_as_username trueRestart Mosquitto:
sudo systemctl restart mosquitto
sudo systemctl status mosquittoQuick test (from a WireGuard peer) on 1883:
mosquitto_pub -h 10.8.0.1 -p 1883 -u your_username -P your_password -t test -m "Hello over WireGuard"
mosquitto_sub -h 10.8.0.1 -p 1883 -u your_username -P your_password -t testQuick test (TLS) on 8883:
mosquitto_pub -h YOUR_PUBLIC_HOST -p 8883 --cafile /etc/mosquitto/certs/ca.crt \
-u your_username -P your_password -t test -m "Hello over TLS"For Android, use a certificate chain that the phone trusts (public CA) or bundle/ship your CA certificate if you use a private CA.
cd lights-timer/RaspberryPi/aqua_topic_provider/
make
# Edit service file (paths, user, etc.)
sudo nano mqtt-devices-provider.service
sudo cp mqtt-devices-provider.service /etc/systemd/system/
sudo systemctl enable mqtt-devices-provider
sudo systemctl start mqtt-devices-providerExample mqtt-devices-provider.service:
[Unit]
Description=MQTT device discovery service
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/home/pi/Documents/lights-timer/RaspberryPi/aqua_topic_provider
WorkingDirectory=/home/pi/Documents/lights-timer/RaspberryPi/aqua_topic_provider/provider
Restart=always
RestartSec=5
User=pi
[Install]
WantedBy=multi-user.target- Flash via Arduino IDE (2.3.x) using the Earlephilhower RP2040 core.
- Configure:
- Wi‑Fi SSID/password (LAN uplink)
- WireGuard keys + peer endpoint (server) + allowed IPs (
10.8.0.0/24) - MQTT broker address:
10.8.0.1, port1883 - MQTT username/password
- Open in Android Studio (Gradle sync).
- Supports Android 6.0+.
- Configure broker host/port:
YOUR_PUBLIC_HOST:8883(TLS)
- Provide MQTT username/password.
- Provide CA/server certificate settings as required by your TLS deployment.
This project includes https://github.com/DaveGamble/cJSON for lightweight JSON parsing on embedded devices.
License: MIT (see cJSON/LICENSE)
MIT License – see LICENSE file.