Mastering Your Heartbeat: Architecting a High-Frequency Health Monitoring System with InfluxDB and Grafana

Published: (April 23, 2026 at 08:23 PM EDT)
3 min read
Source: Dev.to

Source: Dev.to

Introduction

High‑frequency health monitoring generates thousands of data points per minute from sensors such as heart‑rate, blood‑oxygen (SpO₂), and electrocardiogram (ECG). Storing this data in a traditional relational database quickly becomes impractical. A time‑series database (TSDB) like InfluxDB provides the write throughput and storage efficiency needed for such workloads.

Architecture Overview

The data flow consists of:

graph TD
    A[Wearable Sensors / IoT Node] -->|MQTT/HTTP| B(Telegraf Collector)
    B -->|Line Protocol| C{InfluxDB 2.x}
    C -->|Flux Query| D[Grafana Dashboard]
    C -->|Retention Policy| E[Downsampled Long‑term Storage]

    subgraph "Data Engineering Layer"
    B
    C
    E
    end

    style C fill:#f96,stroke:#333,stroke-width:2px
  • Wearable Sensors / IoT Node – emit data via MQTT or HTTP.
  • Telegraf – universal data collector that receives the data and writes it to InfluxDB using the line protocol.
  • InfluxDB 2.x – stores raw measurements and runs background tasks for down‑sampling.
  • Grafana – visualizes the data with Flux queries.

Prerequisites

  • Docker & Docker Compose
  • Basic knowledge of IoT protocols (MQTT/HTTP)
  • InfluxDB 2.x, Telegraf, Grafana

Docker Compose Setup

Create a docker-compose.yml file to orchestrate the services:

version: '3.8'
services:
  influxdb:
    image: influxdb:2.7
    ports:
      - "8086:8086"
    volumes:
      - influxdb-data:/var/lib/influxdb2
    environment:
      - DOCKER_INFLUXDB_INIT_MODE=setup
      - DOCKER_INFLUXDB_INIT_USERNAME=admin
      - DOCKER_INFLUXDB_INIT_PASSWORD=password123
      - DOCKER_INFLUXDB_INIT_ORG=my-health
      - DOCKER_INFLUXDB_INIT_BUCKET=raw_vitals

  telegraf:
    image: telegraf:latest
    volumes:
      - ./telegraf.conf:/etc/telegraf/telegraf.conf:ro
    depends_on:
      - influxdb

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    depends_on:
      - influxdb

volumes:
  influxdb-data:

Running docker compose up -d will start a reproducible, isolated environment.

InfluxDB Schema Design

For health vitals, organize data into tags (metadata) and fields (measurements).

Measurement: vitals
Tags:        patient_id="user_01", device_type="watch_v2"
Fields:      bpm (float), spo2 (float), ecg_mv (float)

Tags are indexed and enable efficient queries; fields store the actual numeric values.

Telegraf Configuration

Save the following as telegraf.conf (TOML format). It configures an HTTP listener to receive JSON payloads and forwards them to InfluxDB.

[[inputs.http_listener_v2]]
  service_address = ":8080"
  path = "/telegraf"
  methods = ["POST"]
  data_format = "json"
  tag_keys = ["patient_id", "device_type"]

[[outputs.influxdb_v2]]
  urls = ["http://influxdb:8086"]
  token = "${INFLUX_TOKEN}"
  organization = "my-health"
  bucket = "raw_vitals"

Downsampling with InfluxDB Tasks

Storing every ECG sample for years is costly. Keep raw data for 24 hours and downsampled data for long‑term analysis. The following Flux task creates 1‑minute averages and writes them to a separate bucket.

option task = {name: "Downsample_Vitals", every: 1m}

from(bucket: "raw_vitals")
  |> range(start: -task.every)
  |> filter(fn: (r) => r._measurement == "vitals")
  |> mean()
  |> set(key: "_measurement", value: "vitals_1m_avg")
  |> to(bucket: "long_term_vitals")

Grafana Setup

  1. Add InfluxDB as a data source (choose Flux as the query language).
  2. Create a dashboard panel with the following Flux query to visualize heart‑rate (bpm):
from(bucket: "raw_vitals")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r["_measurement"] == "vitals")
  |> filter(fn: (r) => r["_field"] == "bpm")
  |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
  |> yield(name: "mean")

Alerting

Set up an alert rule in Grafana (or via InfluxDB Tasks) to trigger when the heart‑rate exceeds a threshold, e.g., bpm > 150 for more than 5 minutes. The alert can send notifications to Slack, Discord, or other channels.

Conclusion

By combining InfluxDB, Telegraf, and Grafana, raw sensor signals are transformed into actionable health insights. This stack provides high write throughput, efficient storage, and flexible visualization—making it well‑suited for personal or research‑grade health monitoring.

What’s Next?

  • Add an AI layer (e.g., Python) to detect arrhythmias in real time.
  • Explore multi‑tenant architectures and encryption‑at‑rest for HIPAA‑compliant deployments.
0 views
Back to Blog

Related posts

Read more »