Skip to Content
IoT App DevelopmentBuild Your First App

Build Your First App

This guide walks through the typical workflow for building an IronFlock app that collects data from edge devices and displays it on real-time dashboards. By the end you will have a data model, edge logic, a user-facing configuration form, and live charts — all connected through the project database.

1. Design the Data Model

Start in the .ironflock/data-template.yml file. Think about two categories of tables:

  • Entity tables — track the current state of things (devices, machines, connections). Rows are appended on every change; maintainLatestFlagFor keeps the newest entry marked.
  • Time-series tables — collect measurements over time (sensor readings, metrics). Every row is a new data point with a timestamp.
data: tables: # Entity table: one row per device, latest state always queryable - tablename: devices maintainLatestFlagFor: ['device_key'] columns: - id: tsp dataType: timestamp - id: device_key dataType: string - id: status dataType: string - id: device_name dataType: string - id: deleted dataType: boolean # Entity table: user-configured Modbus servers - tablename: modbus_servers maintainLatestFlagFor: ['server_id'] columns: - id: tsp dataType: timestamp - id: server_id dataType: string - id: host dataType: string - id: port dataType: numeric - id: deleted dataType: boolean # Time-series table: periodic readings from connected hardware - tablename: readings columns: - id: tsp dataType: timestamp - id: server_id dataType: string - id: metric dataType: string - id: value dataType: numeric

2. Set Up a Test Environment

To test your app you need a dev environment in a project with at least one online device:

  1. Click Develop on the app detail page to open the Cloud IDE.
App detail page showing the Develop button
  1. Pick an online device from any project you have access to.
Device picker showing available devices across projects
  1. Click Create Backend in the side panel to create a dev environment in that project’s database.
Side panel with Edge Development controls and Create Backend button

This instantiates the tables defined in your data-template.yml inside the project’s database. You can inspect them in the project’s Fleet Database view.

The Cloud IDE gives you a full VS Code environment with a file explorer, editor, terminal, and the Edge Development panel for building and deploying to your device.

Cloud IDE with code editor and Edge Development panel

3. Write the Edge Code

Your Docker container runs on the device and uses the IronFlock SDK to interact with the project database.

Register the device on startup

When the edge component starts, append a row to the devices entity table so the dashboard knows the device is online:

import asyncio from ironflock import IronFlock async def main(): # Register this device as online await flock.append_to_table("devices", { "device_key": os.environ.get('DEVICE_KEY'), "tsp": now, "status": "online", "device_name": os.environ.get('DEVICE_NAME'), "deleted": False }) # ... rest of your logic flock = IronFlock(mainFunc=main) flock.run()

Because devices uses maintainLatestFlagFor: ['device_key'], the previous status row for this device is automatically superseded. Widgets that filter by latest_flag = true always show the current state.

React to user configuration

Users can add Modbus servers through a form on the board (see step 4). Your edge code subscribes to the modbus_servers table and acts on new entries:

async def main(): # ... device registration ... # Read existing Modbus servers existing = await flock.getHistory("modbus_servers", { "limit": 1000, "filterAnd": [ {"column": "latest_flag", "operator": "=", "value": True}, {"column": "deleted", "operator": "IS", "value": None} ] }) for server in existing: create_modbus_connection(server) # React to new servers in real time def on_server_change(*args, **kwargs): server = args[0] if args else kwargs if server.get("deleted"): delete_modbus_connection(server["server_id"]) else: create_modbus_connection(server) await flock.subscribe_to_table("modbus_servers", on_server_change)

Collect time-series data

Once a Modbus connection is established, poll periodically and write the readings to the readings table:

async def modbus_poll_loop(server_id, client): while True: values = client.read_registers() for metric, value in values.items(): await flock.publish_to_table("readings", { "server_id": server_id, "metric": metric, "value": value }) await asyncio.sleep(5)

4. Build the Board

Open the Board Editor and add widgets that connect to your Data Backend tables.

Show device status

Add a Table widget connected to the devices table. Filter by latest_flag = true so it always shows the current state of each device. The table updates automatically when a device comes online or goes offline.

Let users configure Modbus servers

Add a Form widget connected to the modbus_servers table. Configure fields for host and port. When a user fills in the form and submits, a new row is inserted into the modbus_servers table automatically — no backend code needed to handle the form submission.

Your edge code picks up the new row via subscribeToTable (see step 3) and establishes the Modbus connection.

Visualise time-series data

Add a Line Chart widget connected to the readings table. Map tsp to the X-axis and value to the Y-axis. The chart updates in real time as new readings arrive from the devices — no polling or manual refresh required.

How It All Fits Together

┌─────────────────────────────────────────────────────────┐ │ Board (Dashboard) │ │ ┌──────────┐ ┌──────────────┐ ┌───────────────────┐ │ │ │ Table │ │ Form │ │ Line Chart │ │ │ │ devices │ │ modbus_servers │ │ readings │ │ │ └────┬─────┘ └──────┬───────┘ └────────┬──────────┘ │ │ │ │ │ │ └───────┼───────────────┼───────────────────┼─────────────┘ │ │ │ ┌────▼───────────────▼───────────────────▼────┐ │ Project Database │ │ devices │ modbus_servers │ readings │ └────▲───────────────▲───────────────────▲────┘ │ │ │ ┌────┴───────────────┴───────────────────┴────┐ │ Edge Code (on device) │ │ register device → read config → poll data │ └─────────────────────────────────────────────┘

The project database is the single source of truth. The edge code writes to it, the board reads from it in real time, and user actions via forms write back into it. Your edge code can subscribe to those changes to close the loop — no custom API endpoints needed.

Tips

  • Start with entity tables. Get device registration and a status table working before adding time-series collection.
  • Use maintainLatestFlagFor on any table where you need to query current state. It lets you append history and query the latest row without extra code.
  • Add a deleted column to entity tables that users manage through forms, so records can be soft-deleted while preserving history.
  • Use appendToTable for writes that need confirmation (e.g. initial device registration). Use publishToTable for high-frequency telemetry where fire-and-forget is acceptable.
  • Keep time-series tables simple. One timestamp, an identifier for the source, and the measured values. Use transform tables for aggregation.

Next Steps

If your hardware exposes a web-based HMI or configuration interface, you can embed it directly into your IronFlock board using the Embed widget and device tunnels. See Embedding External HMIs for details.

Last updated on