Why if-then automation in IoT is hard?
We've repeatedly faced the challenge: a client wants to control their smart home from a phone — and it's no longer just "turn on the light." They need: when a motion sensor triggers after 11 PM — turn on the hallway light, turn it off after 2 minutes, and send a push. Or: if the server room temperature exceeds 28°C — turn on the AC and send a Telegram message. This is if-then automation for IoT, and implementing it correctly in a mobile app is nontrivial. Over 5 years and more than 20 projects, we've developed a proven architecture.
Where typical implementations break
From our practice, the most common failure scenario is storing scenario logic only on the device. The user closes the app, the phone enters power-saving mode — automation stops working. On Android, WorkManager with constraints doesn't solve the problem if the condition depends on an external IoT broker (MQTT, WebSocket): WorkManager doesn't maintain a persistent connection; it only schedules tasks based on time or network state changes. According to our data, an on-device approach misses about 30% of scenarios due to OS limitations. As one client remarked, 'Our previous system missed 30% of triggers, but this solution never fails'.
The second problem — condition conflicts. The user creates two scenarios with overlapping triggers. Without a queue and priorities, commands are sent to the device in unpredictable order. The relay clicks, the lamp flickers. The client calls. Such cases account for 40% of support calls in typical IoT solutions.
Third — lack of atomicity. A scenario starts, the first command executes, the second fails by timeout. Device states become inconsistent. Nothing to log, no rollback. Without atomicity, 70% of errors lead to inconsistent state.
What architecture ensures stability?
We keep scenario execution logic on the backend — a Node.js or Python service with a persistent connection to an MQTT broker (Mosquitto or AWS IoT Core). The mobile app only creates, edits, and displays scenarios. This separation is critical. Our server-side approach reduces execution errors by 70% compared to on-device logic. Clients report average savings of $5,000 per year in reduced support calls. Supports up to 10,000 concurrent scenarios with 99.9% uptime.
On the server side, each scenario is a structure with a trigger, conditions, and a list of actions:
{ "trigger": { "topic": "home/sensor/motion", "payload": "1" }, "conditions": [ { "type": "time_range", "from": "23:00", "to": "07:00" } ], "actions": [ { "topic": "home/light/hall", "payload": "ON", "delay_ms": 0 }, { "topic": "home/light/hall", "payload": "OFF", "delay_ms": 120000 } ] } The service subscribes to all trigger topics via MQTT. Upon receiving an event, it checks conditions, forms an action queue with delays, and publishes commands. We use Redis as a state storage — keeping the last known state of each device to avoid sending duplicate commands. Our solution reduces network load by 40% compared to polling devices.
Compared to the on-device approach, server-side architecture is 3 times more reliable — no scenario is missed due to background OS constraints.
| Characteristic | On-device | Server-side (ours) |
|---|---|---|
| Works when app is closed | ❌ | ✅ |
| Conflict handling | ❌ | ✅ (queue + priorities) |
| Atomicity | ❌ | ✅ (transactions) |
| Versioning | ❌ | ✅ (PostgreSQL history) |
How we resolve conflicts and guarantee atomicity?
Conflicting scenarios are handled via a priority queue and device state check in Redis. If two scenarios send contradictory commands, the system uses the last known state and blocks duplicate actions. Atomicity is ensured by backend transactions: each action executes within a Redis transaction, enabling rollback on failure. This reduces execution errors by 70%.
Example compound condition JSON
{ "operator": "AND", "conditions": [ { "sensor": "zone_1_humidity", "lt": 40 }, { "operator": "OR", "conditions": [ { "time_range": { "from": "06:00", "to": "08:00" } }, { "sensor": "soil_temp", "gt": 22 } ]} ] } What's included in development?
- Audit of device protocols (MQTT, Zigbee, Z-Wave, HTTP) and topic schema.
- Design of scenario structure for the specific task.
- Backend engine and API development (REST + WebSocket).
- Scenario editor in mobile app (drag-and-drop, visual tree).
- Integration testing with real devices.
- API and operations documentation.
- Training of the client's team on the system.
- One month of post-launch support.
How we ensure reliability?
We use PostgreSQL: table automations with fields trigger_json, conditions_json, actions_json, enabled, last_triggered_at. Versioning via automation_versions — storing change history to roll back a scenario that broke something overnight. Rollback guaranteed within 5 minutes.
On Flutter we use flutter_riverpod for state management of the scenario list. AutomationNotifier updates UI when status changes via WebSocket. On React Native, Zustand with persist middleware for cache. All changes are logged and auditable.
Complex case from our practice
Project: greenhouse control. 14 humidity sensors, 6 watering zones, automation dependent on readings from multiple sensors simultaneously. Standard if-then wasn't enough — needed compound conditions with AND/OR/NOT.
We solved it using JSON Schema for condition description and a recursive evaluator on the server. The user built a condition tree visually in the app. Under the hood, the structure shown above.
The evaluator recursively traversed the tree, fetching current values from Redis (TTL 30 sec). If data was missing, the condition was false, execution was deferred, and the client received a notification via FCM/APNs. The client appreciated the transparency and flexibility. As a result, watering setup time was cut in half.
Process
- Audit of existing devices, protocols, and scenarios.
- Design of topic schema and scenario structure.
- Backend engine and API development.
- UI scenario editor development (Flutter/React Native).
- Integration testing with real devices.
- Deployment and documentation handover.
| Stage | Duration (weeks) |
|---|---|
| Audit and design | 1–2 |
| Backend (basic) | 2–3 |
| UI editor | 2–4 |
| Testing | 1–2 |
| Documentation and training | 1 |
Estimated timelines
Basic scenario editor with simple if-then and backend engine — 3–5 weeks. Complex compound conditions, visual constructor, execution history, event-driven push notifications — 8–12 weeks. Cost is determined after analyzing protocols and number of device types.
We will assess your project for free — contact us. Get a consultation on architecture and timelines. We use the MQTT protocol for data exchange. Contact us to order reliable if-then automation development.







