This project implements a simple(?) IoT system for controlling relay modules using an Android application via MQTT (TLS/x509). The system consists of three main components:
- Android App β graphical user interface for users to manage discovered devices and toggle relays.
- Raspberry Pi Pico W β execution unit that controls physical relays, handles WiFi, MQTT, time sync, and device discovery.
- Raspberry Pi (Provider) β MQTT mosquitto broker, and discovery daemon that detects active Pico W units and updates the Android app via MQTT.
- The system is designed to work within a mosquitto over TLS/x509 certificates.
- Raspberry Pi/mosquitto requires external IP for communication (and opened port 8883).
- Written in Java and uses Kotlin for UI utilities.
- Uses Eclipse Paho MQTT client.
- Dynamically builds device list based on
AQUA_DEVICES_UPDATE
topic. - Subscribes to individual device topics for real-time updates.
- Supports toggling relays and setting time-based schedules.
- Firmware is written in C++,
- JSON parsing is done using
cJSON
(included). - Features:
- WiFiClientSecure + x509 (Earlephilhower core)
- NTP time sync
- state machine
- OLED display (Adafruit_SSD1306)
- MQTT subscribe/publish (PubSubClient)
- EEPROM persistence
- Hardware watchdog
- Discovery detect & responder (UDP)
- OTA updates (ArduinoOTA)
- Written in C and runs as a
systemd
service. - Periodically:
- Broadcasts UDP discovery
- Receives UDP responses from Pico W
- Verifies the availability of Pico W devices (TCP connection in order to keep only active devices on the list)
- 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 |
For the system to operate correctly, the local network and Raspberry Pi must be properly configured:
- WiFi local network must allow broadcast UDP traffic.
Port | Protocol | Purpose | Required |
---|---|---|---|
8883 | TCP | MQTT over TLS | β yes |
1883 | TCP | MQTT without TLS (optional) | |
8266 | TCP | OTA firmware updates (optional) | |
12345 | UDP | Device discovery via broadcast | β yes |
# MQTT over TLS
sudo iptables -A INPUT -p tcp --dport 8883 -j ACCEPT
# (Optional) Plain MQTT
sudo iptables -A INPUT -p tcp --dport 1883 -j ACCEPT
# (Optional) OTA firmware updates
sudo iptables -A INPUT -p tcp --dport 8266 -j ACCEPT
# UDP broadcast discovery
sudo iptables -A INPUT -p udp --dport 12345 -j ACCEPT
# Save firewall rules
sudo netfilter-persistent save
β οΈ If you want to use a different port for discovery or OTA, adjust the rules accordingly.
All MQTT clients (Pico W and Android app) must be able to reach the broker at TCP port 8883.
sudo apt update
sudo apt install libmosquitto-dev libmosquitto1 mosquitto-clients
sudo apt-get install libcjson-dev
sudo apt install mosquitto mosquitto-clients
sudo systemctl enable mosquitto
sudo systemctl start mosquitto
To enable secure MQTT communication, you must configure Mosquitto to use TLS with your own x.509 certificate authority (CA). Here's a generalized and anonymized setup procedure:
sudo iptables -A INPUT -p tcp --dport 8883 -j ACCEPT
sudo netfilter-persistent save
mkdir -p ~/mqtt-certs/{ca,server,config}
cd ~/mqtt-certs
Edit your OpenSSL configuration file (config/server-openssl.cnf
):
[req]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[dn]
C = YOUR_COUNTRY
ST = YOUR_STATE
L = YOUR_CITY
O = YOUR_ORG
OU = YOUR_UNIT
CN = your.mqtt.domain
emailAddress = your@email.com
[req_ext]
subjectAltName = @alt_names
[alt_names]
IP.1 = your.internal.ip
DNS.1 = your.mqtt.domain
Then execute:
# Certificate Authority
openssl genrsa -out ca/ca.key 4096
openssl req -x509 -new -nodes -key ca/ca.key -sha256 -days 3650 -out ca/ca.crt -config config/server-openssl.cnf
# Server Certificate
openssl genrsa -out server/server.key 2048
openssl req -new -key server/server.key -out server/server.csr -config config/server-openssl.cnf
openssl x509 -req -in server/server.csr -CA ca/ca.crt -CAkey ca/ca.key -CAcreateserial \
-out server/server.crt -days 3650 -sha256 \
-extfile config/server-openssl.cnf -extensions req_ext
sudo systemctl stop mosquitto
sudo cp ca/ca.crt server/server.crt server/server.key /etc/mosquitto/certs/
sudo chown -R mosquitto: /etc/mosquitto/certs
sudo chmod 750 /etc/mosquitto/certs
sudo chmod 640 /etc/mosquitto/certs/*.crt /etc/mosquitto/certs/*.key
/etc/mosquitto/mosquitto.conf:
pid_file /run/mosquitto/mosquitto.pid
persistence true
persistence_location /var/lib/mosquitto/
persistence_file mosquitto.db
autosave_interval 300
user mosquitto
log_dest file /var/log/mosquitto/mosquitto.log
include_dir /etc/mosquitto/conf.d
log_type all
connection_messages true
/etc/mosquitto/conf.d/tls.conf:
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
require_certificate false
use_identity_as_username false
allow_anonymous false
/etc/mosquitto/conf.d/plain.conf:
listener 1883
allow_anonymous false
password_file /etc/mosquitto/passwd
To generate a password for Mosquitto, use the following command:
mosquitto_passwd -c /etc/mosquitto/passwd your_username
This will create (or overwrite) the password file and prompt you to enter a password for your_username
.
Make sure the path matches the one used in your Mosquitto configuration (password_file
).
sudo systemctl restart mosquitto
sudo systemctl status mosquitto
# Test TLS connection
mosquitto_pub -h your.mqtt.domain -p 8883 --cafile /etc/mosquitto/certs/ca.crt -u youruser -P yourpass -t test -m "Hello over TLS"
# In a separate console:
mosquitto_sub -h your.mqtt.domain -p 8883 --cafile /etc/mosquitto/certs/ca.crt -u youruser -P yourpass -t test
cd lights-timer/RaspberryPi/aqua_topic_provider/
make
#edit service file - adjust the path to executable, 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-provider
Example 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
Additionally, the Raspberry Pi provider must be executed at least once from the console to initialize and store the MQTT broker credentials.
- Flash via Arduino IDE (2.3.xx) using the Earlephilhower RP2040 core
- Set WiFi and MQTT credentials in
Credentials.h
, and certificate inca_cert.c
. For detailed info, please take a look below.
- Open in Android Studio (and gradle sync).
- Supports Android 6.0+.
- MQTT credentials are requested on first launch.
- temperature & hear and cooling system for aqua tanks?
Project requires Arduino tools library - included as submodule (git clone with --recurse-submodules) Available also here
It is important to copy the contents of the "libraries"
folder into the "libraries"
directory managed by the Arduino environment.
But before that, it is essential to properly configure and complete the content of the following files:
libraries/Credentials/ca_cert.c
and libraries/Credentials/MacHostMapping.h/.cpp
β these must be adapted to:
- the WiFi SSID and password,
- the MQTT broker login/password/IP (or domain),
- the x.509 certificate,
- the MAC-to-hostname mapping and number of relays.
This project includes cJSON for JSON parsing on embedded devices.
cJSON aims to be the simplest and smallest possible JSON parser in C thatβs also fully functional. It supports encoding, decoding, and manipulating JSON data using a lightweight DOM-style tree.
License: MIT (see cJSON/LICENSE
)
MIT License β see LICENSE
file.