Imagine two couriers delivering messages from ESP32 to the server: HTTP courier and MQTT courier. Both carry similar message content, then the server stores each delivery, calculates delivery quality, and shows the comparison on the dashboard.
Technically, firmware in ESP32_Firmware/src/main.cpp sends periodic payloads to POST /api/http-data (HTTP) and broker topic iot/esp32/suhu (MQTT). HTTP path is handled by ApiController::storeHttp, MQTT path is handled by worker mqtt_worker.php, then both are stored idempotently in eksperimens.
1. ESP32
Reads sensor and prepares telemetry packet.
2. HTTP + MQTT
Packet is sent through two different channels.
3. Database
Server stores deliveries and calculates metrics.
4. Dashboard
Comparison results are shown in realtime for analysis.
How Data Flows in This System
Simple view: data moves from device (ESP32), enters server, is stored in database, gets statistical processing, and is finally shown on dashboard.
Technical view: firmware sendHTTP() and sendMQTT() push payloads; HTTP is accepted by ApiController::storeHttp, MQTT is accepted by callback in mqtt_worker.php; data is written via Eksperimen::updateOrCreate; dashboard calls StatisticsService from DashboardController::index.
For general readers: this page explains who sends the data, where it goes, what is calculated, and how the results are read on dashboard.
For technical readers: the system compares MQTT vs HTTP telemetry from ESP32, stores both in MySQL, then runs comparative statistics (summary, reliability, t-test) before rendering charts and analysis panels.
Firmware (ESP32)
File: ESP32_Firmware/src/main.cpp. Sends HTTP and MQTT periodically (default both 10 seconds) with complete telemetry fields and packet sequence.
HTTP Ingress
Route POST /api/http-data -> ApiController::storeHttp, with middleware throttle:http-data and ingest.key.
MQTT Ingress
Not handled by a Laravel controller. Incoming MQTT is processed by standalone worker mqtt_worker.php then upserted into eksperimens.
Dashboard
Route GET / -> DashboardController::index, statistics are computed by StatisticsService, frontend is in resources/views/dashboard.blade.php.
Actual Architecture (Code-Based)
Simple view: there are two delivery channels from ESP32, then both channels meet in database for joint analysis.
Technical view: the diagram below follows runtime paths that actually exist in this repository with no assumptions beyond code.
This inline SVG follows actual code paths: latency is calculated in backend ingest (HTTP controller + MQTT worker), while T-Test runs in StatisticsService before dashboard rendering.
Visual Timeline: HTTP Request/Response vs MQTT Publish/Subscribe
Simple view: both protocols start from sensor timestamp, but the travel pattern differs. HTTP waits for request response, while MQTT publishes and is then processed by subscriber worker.
Technical view: this timeline maps timestamp_esp, transmit phase, server receive moment, and where latency_ms is computed in backend ingest. HTTP path maps to sendHTTP() + ApiController::storeHttp; MQTT path maps to sendMQTT() + mqtt_worker.php.
Laravel Route Map (Current)
Method
Path
Handler
Purpose
GET
/
DashboardController@index
Main dashboard
POST
/api/http-data
ApiController@storeHttp
HTTP ingest from ESP32
GET
/simulation
SimulationController@index
Simulation UI
POST
/simulation/start|stop|tick|reset
SimulationController
Simulation control
GET/POST
/reset-data
DashboardController
Reset real telemetry
GET
/admin/login
AdminConfigController@loginForm
Admin login
GET/POST/PATCH/DELETE
/admin/config/*
AdminConfigController
Runtime + firmware provisioning
GET
/doc
view('doc')
This technical documentation page
HTTP Controller and MQTT Worker
Simple view: HTTP gate is handled by Laravel, while MQTT gate is handled by a dedicated worker. Both validate data before storing it.
Technical view: API route uses throttle:http-data + ingest.key middleware. MQTT runs as separate subscriber process with manual validation, then both perform idempotent upsert into the same table.
HTTP path (ApiController::storeHttp)
Validates all required telemetry fields with range constraints.
Computes latency_ms from server UTC time minus timestamp_esp.
Also subscribes debug topic iot/esp32/debug and updates storage/app/esp32_debug_heartbeat.json.
Important note: this repository has no dedicated Laravel MQTT ingest controller. MQTT ingestion is handled by standalone process mqtt_worker.php.
JSON Payload Structure Used in Runtime
Simple view: payload is "package content" carried from ESP32 to server. It contains primary sensor data and additional fields for network-quality diagnostics.
Technical view: firmware payload builder (fillProtocolPayload()) always emits required telemetry fields plus diagnostics such as RSSI, TX duration, payload bytes, and send success/fail counters.
This section is intentionally two-layered: first paragraph for non-technical understanding, second paragraph for technical accuracy based on code.
Latency
Simple view: latency is how long it takes data to travel from the device to the server. Smaller latency means faster delivery.
Technical view: both HTTP and MQTT compute latency_ms = abs(server_utc - timestamp_esp) using Carbon::floatDiffInMilliseconds() in ApiController and mqtt_worker.php, then store it in eksperimens.latency_ms.
Power Consumption
Simple view: the system estimates "energy cost" each time ESP32 sends data. This is not a direct electrical meter; it is an estimate based on transmission conditions.
Technical view: firmware computes powerMw = voltage * totalCurrentMa in estimateProtocolPower() using RSSI, payload size, TX duration, protocol overhead, fail ratio, temperature, and humidity. It is sent as daya then stored in backend as daya_mw.
Reliability / Packet Delivery Ratio
Simple view: reliability shows how consistently data arrives without loss. If many packet numbers are missing, reliability decreases.
Technical view: backend computes sequence reliability from packet_seq per device (received / expected * 100) with reboot/jump segmentation rules. Final score combines sequence, field completeness, and transmission health via combineReliability().
Independent Sample T-Test
Simple view: T-Test helps answer whether MQTT and HTTP differences are likely real, not just random short-term fluctuations.
Technical view: StatisticsService::tTest() calculates pooled variance, standard error, and t_value for latency_ms and daya_mw. Significance is decided with fixed threshold |t| > 1.96, while p_value is shown as an approximate value.
Latency Calculation Mechanism
Both HTTP controller and MQTT worker use the same latency formula.
HTTP and MQTT have different protocol overhead values (HTTP is higher).
Penalty increases as fail ratio rises (httpSendFail/mqttSendFail).
Transmission duration, payload size, RSSI, and environment deltas affect the estimate.
Formula is deterministic (current firmware path uses no random baseline).
Packet Delivery Ratio (Backend Reliability)
The backend does not persist a separate field named PDR, but sequence reliability is calculated as received / expected * 100 and used in total reliability score.
Simple view: weaker signal, longer transmission, and larger payload generally increase estimated power.
Technical view: the components above follow the real terms in firmware estimateProtocolPower().
Example 4: Reading p-value and significance
Simple view: if result is significant, it means the two communication paths have a statistically meaningful performance difference.
Technical view: current code determines significance using |t_value| > 1.96. p_value is shown as an approximation to support interpretation (not exact Student-t computation for all df).
Why Was This System Designed This Way?
Why compare MQTT and HTTP
Simple view: research needs fair comparison. Similar payload is sent through two different paths so we can observe which one is faster and more stable.
Technical view: firmware sends matching fields to HTTP and MQTT, backend stores them in the same table/schema (distinguished by protokol) so cross-protocol statistics can be compared directly.
Why MQTT worker is separated
Simple view: MQTT path is "always listening", so it fits better as a dedicated always-on process.
Technical view: this repository intentionally has no Laravel MQTT ingest controller; MQTT ingest runs in standalone mqtt_worker.php with reconnect loop, fallback hosts, and lock file to prevent duplicate workers.
Why use T-Test
Simple view: averages alone are not enough. T-Test checks whether the difference between protocols is statistically strong enough.
Technical view: StatisticsService computes independent sample t-tests for latency and power, then dashboard displays key parameters (N, mean, variance, std dev, t-value, p-value, interpretation).
Database Structure and Table Relations
devices (id PK)
|-< eksperimens.device_id FK (1:N)
|-< simulated_eksperimens.device_id FK (1:N)
'- 1:1 device_firmware_profiles.device_id FK (unique)
app_settings (standalone key-value runtime overrides)
Unique key for idempotent ingestion: (device_id, protokol, packet_seq).
Simulation telemetry table
simulated_eksperimens mirrors the same telemetry shape with the same unique key, but remains isolated from real telemetry table.
Query examples (runtime troubleshooting)
-- Latest real rows by protocol
SELECT id, device_id, protokol, packet_seq, latency_ms, daya_mw, timestamp_server
FROM eksperimens
WHERE protokol IN ('MQTT', 'HTTP')
ORDER BY COALESCE(timestamp_server, created_at) DESC
LIMIT 20;
-- Required field completeness audit for MQTT scope
SELECT
COUNT(*) AS total_rows,
SUM(CASE WHEN suhu IS NULL THEN 1 ELSE 0 END) AS missing_suhu,
SUM(CASE WHEN kelembapan IS NULL THEN 1 ELSE 0 END) AS missing_kelembapan,
SUM(CASE WHEN packet_seq IS NULL THEN 1 ELSE 0 END) AS missing_packet_seq
FROM eksperimens
WHERE UPPER(protokol) = 'MQTT';
Flow: Data Ingest to Dashboard Rendering
Simple view: after data is saved into database, the system transforms it into concise numbers so users can quickly see which protocol is faster, more power-efficient, and more stable.
Technical view: DashboardController::index pulls protocol data from telemetry model, calls StatisticsService for summary/reliability/t-test, prepares chart payloads, then sends all results to resources/views/dashboard.blade.php.
ESP32 sends HTTP and MQTT payloads with full telemetry fields.
Rejects df=0 and standard error denominator=0 cases.
Reliability scope prioritizes rows with non-null packet_seq when available.
Required field completeness checks 15 telemetry fields consistently for MQTT and HTTP.
System Limitations (Based on Current Code)
p_value in T-test uses approximation, especially coarse for small df.
Critical value is fixed at +/-1.96 in code, not dynamically adjusted by df.
daya_mw is a firmware-side estimate, not direct electrical sensor measurement.
Latency depends on ESP32 clock validity; NTP drift or unsynced epoch affects metric quality.
Sequence reliability uses segmentation rules (reboot/jump handling), so very large jumps become new segments instead of continuous loss.
MQTT ingestion depends on standalone worker process availability; if worker is down, MQTT telemetry is not persisted.
This documentation is implementation-bound; update this page whenever telemetry schema, formulas, or runtime paths change.
Glossary / Glossary
Each term is written in two layers: simple explanation for general readers, followed by technical explanation based on actual repository implementation.
idempotent upsert
Simple: sending the same data repeatedly does not create duplicates.
Technical: HTTP and MQTT use updateOrCreate with identity (device_id, protokol, packet_seq), reinforced by database unique index on the same key combination.
packet_seq
Simple: packet order number so the system can detect missing or repeated packets.
Technical: firmware increments httpPacketSeq and mqttPacketSeq on each send; backend uses this value for idempotent dedup and sequence reliability calculation.
window analysis
Simple: the system only takes a recent subset of data so analysis remains lightweight and relevant.
Technical: DASHBOARD_ANALYSIS_WINDOW (default 50) is used by StatisticsService::getProtocolData(); chart uses DASHBOARD_CHART_WINDOW (default 0 (unlimited)).
latency_ms
Simple: travel time of data from ESP32 to server, in milliseconds.
Technical: calculated as abs(server_utc - timestamp_esp) in ApiController::storeHttp and mqtt_worker.php, then stored in latency_ms column.
daya_mw
Simple: estimated power usage during data transmission.
Technical: firmware computes daya via estimateProtocolPower() then backend stores it in daya_mw. This is a model estimate, not direct electrical sensor reading.
Independent Sample T-Test
Simple: statistical test to check whether differences between two data groups are scientifically strong enough.
Technical: StatisticsService::tTest() computes pooled variance, standard error, and t_value for MQTT vs HTTP data on latency_ms and daya_mw metrics.
p-value
Simple: a number that helps judge whether the observed difference could be random chance.
Technical: in this project, p_value comes from approximation function calculatePValue() (normal CDF for large df, coarse bins for small df), so it is indicative.
publish/subscribe
Simple: sender puts message into a topic, and subscribed receivers process it.
Technical: firmware sendMQTT() performs publish to configured topic, then mqtt_worker.php performs subscribe and stores payload into database.
request/response
Simple: sender asks server to process data, then server replies with result status.
Technical: firmware sendHTTP() posts to /api/http-data, ApiController::storeHttp handles validation/upsert, then returns JSON response with HTTP status code.