[Perl] DAQ system for the FAPG.
FAPG DAQ system
Table of Contents
Overview
The goal of this project is to deploy a DAQ network at the /Ferme Aquaponique du Pays de Gex/ (FAPG). DAQ sensor nodes periodically send readings to a central DAQ hub. An external VPS obtains these readings, and presents them on a dashboard accessible via the web.
Architecture
@startuml
title FAPG DAQ - from reading to web dashboard
actor "Farm user/browser" as Browser
participant "EZO probe\npH / EC / DO / ORP" as Probe
participant "Pi Zero 2W\nfapg-daq service" as Zero
participant "Pi 5\nMosquitto MQTT broker" as Broker
participant "VPS\nMQTT subscriber service" as VPSSubscriber
database "Readings database\nSQLite / PostgreSQL" as DB
participant "VPS\nLive dashboard app" as Dashboard
== DAQ acquisition ==
Zero -> Probe : Request UART reading
Probe --> Zero : Return raw sensor value
Zero -> Zero : Normalize reading
== MQTT publication ==
Zero -> Broker : MQTT PUBLISH\nfapg/daq/<probe>/<node>/reading\nvalid reading JSON payload
Zero -> Broker : MQTT PUBLISH\nfapg/daq/<probe>/<node>/status\nnode/probe status JSON payload
Broker -> Broker : MQTT PUBLISH\nfapg/daq/hub/<node>/status\nhub status JSON payload
note right of Zero
Example reading payload:
{
"schema": "fapg.daq.reading.v1",
"node": "fapg-zero-ph-01",
"probe": "ph",
"value": 7.12,
"unit": "pH",
"timestamp": "2026-06-27T13:45:00Z"
}
Example status payload:
{
"schema": "fapg.daq.status.v1",
"node": "fapg-zero-ph-01",
"probe": "ph",
"status": "probe_error",
"timestamp": "2026-06-27T13:45:05Z",
"error": "timeout waiting for EZO response"
}
end note
VPSSubscriber -> Broker : MQTT SUBSCRIBE\nfapg/daq/#
Broker --> VPSSubscriber : MQTT MESSAGE\nreading/status topic + JSON payload
VPSSubscriber -> VPSSubscriber : Validate topic and payload\nparse probe, node, value/status, timestamp
== Database storage ==
VPSSubscriber -> DB : INSERT reading
VPSSubscriber -> DB : INSERT node status
DB --> VPSSubscriber : OK
== Live dashboard presentation ==
Browser -> Dashboard : Open HTTPS dashboard
Dashboard -> DB : SELECT recent readings
DB --> Dashboard : Return recent readings
Dashboard --> Browser : Initial HTML + Chart.js data
loop live updates
VPSSubscriber -> Dashboard : Notify new reading\nWebSocket / SSE / app event
Dashboard --> Browser : Push new reading\nWebSocket or Server-Sent Events
Browser -> Browser : Append point to Chart.js chart
end
@enduml
#+RESULTS: file:docs/architecture.png
Hosts
Raspberry Pi Zero 2W
These hosts collect DAQ readings, and publish them via MQTT on the LAN.
| Pi Zero | Probe | |---------+-------| | 01 | PH | | 02 | EC | | 03 | DO | | 04 | ORP |
Raspberry Pi 5
This host brokers MQTT messages sent on the LAN.
VPS
This host establishes a VPN connection with the Pi 5 host, subscribes to all MQTT topics, saves messages to a database, and exposes a realtime web dashboard available over the internet.
MQTT Topics
Valid probe measurements are published only on:
fapg/daq/<probe>/<node>/reading
Node/probe health is published separately on:
fapg/daq/<probe>/<node>/status
The DAQ hub publishes its own heartbeat status on:
fapg/daq/hub/<node>/status
Status payloads use schema fapg.daq.status.v1. A recent ok status means the node is reachable; for probe nodes it also means the node is publishing valid readings. A recent probe_error status means the node is reachable on the farm network, but the probe or USB serial path is not returning a valid reading. If the dashboard has no recent status for a node or the DAQ hub, it treats that system as unreachable.