
Case study
Real-Time Environmental Monitoring and Asset Tracking Platform for a UK Logistics Operator
Plexteq designed and built a multi-tenant IoT platform for a UK warehouse and logistics company that needed continuous visibility across its distributed facilities.
The platform collects environmental readings from every site, tracks tagged assets by zone over Bluetooth Low Energy, and raises an alert when a condition goes out of range. Operations staff use it through a web portal, a mobile app, and a natural-language assistant.
Project Highlights
Industry
Warehousing and logistics
Market
United Kingdom
Cooperation
2024 – 2025
Expertise
IoT, real-time stream processing, data engineering, web and mobile development, AI integration, cloud infrastructure, DevOps
Technologies
Apache Flink, Confluent Cloud, HiveMQ Cloud (MQTT), PostgreSQL, ADLS Gen2, Next.js, React Native, Expo EAS, Azure, BLE
Business Challenge
The client operates a network of distributed warehouses where internal conditions impact inventory, personnel, and infrastructure. These conditions change frequently. The client required centralized, real-time visibility across all sites.
The client also needed room-level asset location tracking within each building, using Bluetooth Low Energy tags and gateways.
Three requirements shaped the work:
-
Self-service installation. Site staff needed to install devices, register them via mobile, and access data without on-site engineering support.
-
Reliable alerts. The system needed to send a single alert at the start and end of each incident, avoiding excessive notifications.
-
Scalable cost. The platform needed to remain affordable at pilot scale, manageable by a small team, and scalable as needed.
The platform required multi-tenancy from the initial release. Separate customer accounts share a single pipeline under two subscription tiers, with strict data isolation.
Temperature (°C)
Goods held outside their permitted range can be damaged or rejected
Gas concentrations (ppm)
Air quality in enclosed spaces is a staff safety matter.
Light and UV exposure (lux; UV index)
Prolonged exposure degrades sensitive goods and packaging.
Noise levels (dB(A))
Sustained noise is an occupational exposure that has to stay within limits.
Relative humidity (% RH)
Damp air leads to condensation, mould, corrosion and weakened packaging.
Air pressure and HVAC performance (hPa)
Pressure shows whether ventilation is working before temperature and air quality start to drift.
Water and flood detection (Wet or dry state)
A leak caught in minutes costs far less than one found the next morning.
Key Challenges
#1. Noisy location signals
BLE signal strength fluctuates, causing tags near doorways to appear to move between rooms and brief spikes from nearby movement. Simple strongest-signal logic results in unreliable zone histories.
#2. Alert storms
Sensors stuck above thresholds can generate thousands of notifications without deduplication.
#3. High data volume from a small deployment
Tags are scanned every 2 seconds and gateways report every 15 seconds. A pilot with 25 gateways, 100 tags, and 10 sensors generates approximately 195 million MQTT messages and 486 GB per month, averaging 75 messages per second with bursts over 300.
#4. No data loss during downtime
The pipeline must withstand maintenance, upgrades, and outages without losing or duplicating data.
Solution Delivered
Plexteq delivered a complete solution, including device connectivity, stream processing, storage, web and mobile applications, the AI assistant, and supporting Azure-hosted infrastructure.

Gateways aggregate tag signals into MQTT, sensors publish directly, Kafka buffers the stream, and a single Flink job writes to all three data stores. The portal, mobile app, and AI assistant access data from Cosmos DB and PostgreSQL via a unified API.
↳ Processing engine
Three architectures were evaluated before implementation.
The team selected self-hosted Flink to meet client requirements. All self-hosted components, including Flink, the web portal and API, and the notification service, run in Azure Kubernetes Service (AKS). Self-hosting enables use of the DataStream API, which supports the custom keyed state and process functions required for zone tracking.
Databricks
Capable, but oversized for this stage. Cold-start latency on the SQL warehouse and a heavy operational surface.
Container application
Simplest to run. Loses BLE state on restart, gives no backpressure visibility and needs scheduled batch jobs for aggregates.
Apache Flink, self-hosted
Keyed state, continuous aggregation, built-in backpressure and exactly-once semantics. Chosen.
↳ From BLE tag to broker
Tags do not connect directly to the platform. They broadcast, and gateways aggregate these signals into MQTT.
This approach allows many tags to share a limited number of connections. At pilot scale, 100 tags and 10 sensors connect to the broker through 35 MQTT connections. Tags require no network configuration.
Environmental sensors do not require a gateway. Each sensor connects directly to HiveMQ Cloud and publishes approximately three small messages per minute under the environmental/ topic tree. Broker access rules separate device types by topic tree.
The broker and Kafka serve distinct roles. HiveMQ Cloud interfaces with devices, handling MQTT communication, device authentication, topic rule enforcement, and configuration commands. Kafka interfaces with the pipeline: a Confluent MQTT source connector bridges all messages, retaining them for 7 days as a replayable log. This log enables Flink to stop, restart, and resume without data loss or duplication.
Tags advertise
Each tag on a tracked asset broadcasts a BLE advertisement every 2 seconds. Tags with temperature and humidity sensors report those readings the same way.
Gateways listen
Each gateway in range receives the advertisement and records the signal strength (RSSI). Multiple gateways typically detect a single tag simultaneously, enabling accurate zone resolution.
Gateways batch
Each gateway buffers received data and publishes every 15 seconds. To minimize payload size, each cycle is divided into approximately 45 MQTT messages of 2.5 KB, each containing about 13 tag readings.
One session per gateway
Each gateway maintains a single MQTT connection to HiveMQ Cloud over TLS and publishes under the ble/ topic tree, scoped to that gateway.
↳ Recurring, Location-Aware Charging
A single Flink job consumes data from Kafka, routes messages by device type, and processes four parallel paths.
State is stored in RocksDB and checkpointed to Azure Blob Storage. After a restart, Flink resumes from the last checkpoint and restores Kafka offsets with exactly-once semantics. If a downstream store slows, backpressure automatically throttles the Kafka consumer, preventing data loss or unbounded queuing.

↳ Recurring, Location-Aware Charging
We evaluated three methods to prevent tags from rapidly switching zones: a consecutive-window threshold, a majority vote, and a majority vote with a signal-strength margin. The third approach was selected.
A neighboring zone receives a vote only if its signal exceeds the current zone by a set margin, typically 6 dBm. The tag transitions when the new zone wins 3 out of the last 5 windows. Brief door openings do not trigger movement, but a tag left in a new zone moves within 90 to 150 seconds.
Different sites require different behaviors. Warehouses tracking forklifts prioritize fast transitions, while offices tracking shared equipment prioritize stability. Each account configures this setting using a slider in the portal.

The logic operates as a Flink keyed process function with one state partition per tag. This state is included in every checkpoint, preserving zone history after restarts. Slider adjustments take effect within approximately 60 seconds.
↳ Recurring, Location-Aware Charging
Users interact with the assistant in plain language. The assistant operates through the Vercel AI Gateway, with the Next.js API as a proxy, and performs three functions:
-
Creates alert rules. "Alert me if the temperature goes above 25 degrees after 5 PM during weekdays" becomes a structured rule.
-
Answers data questions. "What was the average temperature in warehouse 3 last week?" becomes a query against the aggregate tables and a readable answer.
-
Explains alerts. "Why did this alert fire?" returns the readings around the event in plain language.
The assistant is purpose-built and not a general-purpose chatbot. It declines off-topic requests, filters queries by account to ensure tenant data isolation, and saves rules only after user review and confirmation.
↳ Recurring, Location-Aware Charging
Authentication and authorization. Firebase Auth provides email, social login, and multi-factor authentication. The API validates the token on every request and checks the user's role in PostgreSQL.
Tenant isolation. Every table and document carries the account ID. Flink state is partitioned by device or tag, each of which belongs to one account. The archive is partitioned by account at the path level.
Delivery pipeline. Azure DevOps builds Docker images, deploys them to AKS, and upgrades the Flink job through savepoints, so state is preserved across releases.
Platform services. Secrets are kept in Azure Key Vault, logs and alerts in Azure Monitor, and Microsoft Defender for Cloud covers the cluster and databases.
Key Results
60 sec.
new device live after registration
7 days
buffer while processing is offline, with no readings lost or duplicated
195M messages/ month
throughput at pilot scale
£1k
infrastructure cost
Business Outcome
The client now has a unified platform that displays the condition of every facility and the location of each tagged asset, running on about £1,000 of monthly cloud infrastructure before scaling.
Three additional outcomes matter for future development.
-
Consolidate seven types of environmental risk and asset location in one platform. Site teams operate from a single dashboard.
-
A data asset from day one. All raw and validated readings are archived permanently, supporting analytics, regulatory export, and investigations.
-
A clear path to scale. The Flink job can be split by workload, the processing tier scaled within the Kubernetes cluster, and storage tiering maintained at £35 to £45 per month after one year.
For real-time visibility across distributed facilities or equipment, contact us.
