{"id":55448,"date":"2026-07-18T15:14:52","date_gmt":"2026-07-18T22:14:52","guid":{"rendered":"https:\/\/www.griddb.net\/?p=55448"},"modified":"2026-07-22T15:31:29","modified_gmt":"2026-07-22T22:31:29","slug":"vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud","status":"publish","type":"post","link":"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/","title":{"rendered":"VitalWatch: Real-Time Wearable Health Monitoring with GridDB Cloud"},"content":{"rendered":"<p>\n> <strong>Medical Disclaimer:<\/strong> All health metric estimations in this project (blood pressure, blood sugar) are simplified rule-based simulations for demonstration and educational purposes only. They are not clinically accurate and should never be used for real medical decision-making.\n<\/p>\n<p>This blog is the longer version of the hackathon entry from VitalWatch. You can see their original submission here: <a href=\"https:\/\/gallery.griddb.net\/projects\/vitalwatch.md\">https:\/\/gallery.griddb.net\/projects\/vitalwatch.md<\/a><\/p>\n<h2 id=\"introduction\">Introduction<\/h2>\n<p>\nIn healthcare, early warning often means the difference between a manageable situation and a critical emergency. Wearable devices like smartwatches and fitness bands now collect continuous streams of biometric data \u2014 heart rate, blood oxygen, temperature, and activity level \u2014 all day long.\n<\/p>\n<p>\nWhile there is no shortage of data, most systems fail by evaluating each vital sign in isolation. They flag a high heart rate or a low SpO2 reading independently, without asking the obvious follow-up question: <strong>are these two changes happening at the same time, and in a physiologically connected way?<\/strong>\n<\/p>\n<p>\nA standalone elevated heart rate reading might mean the wearer just walked upstairs. But if heart rate rises <em>and<\/em> SpO2 simultaneously drops <em>and<\/em> body temperature climbs \u2014 that is a physiological chain event, not a coincidence. Most dashboards miss that story.\n<\/p>\n<p>\nVitalWatch addresses exactly this gap. Rather than building another static alert panel, we built a <strong>Wearable Health Intelligence Layer<\/strong> on top of GridDB Cloud that stores continuous vital sign streams, detects physiological chain events across multiple vital signs, and estimates derived health metrics like blood pressure and blood sugar from the raw sensor data.\n<\/p>\n<h2 id=\"why-time-series-databases-matter-for-wearable-health-iot\">Why Time-Series Databases Matter for Wearable Health IoT<\/h2>\n<p>\nA standalone SpO2 reading of 91% doesn&#8217;t tell the whole story. If it dropped from 98% in twenty minutes, it could indicate respiratory distress; if it has safely fluctuated between 90-92% for hours, it might just be a resting artifact. Evaluating sequences of readings over time provides the necessary context to tell the difference.\n<\/p>\n<p>\nWearable devices generate this time-series data continuously \u2014 potentially dozens of readings per minute across multiple sensors. Traditional relational databases, optimized for structured record storage and joins, were not designed for the high-frequency append-heavy workloads that wearable telemetry produces. They can struggle with the combination of write volume, timestamped queries, and time-window aggregations that health monitoring requires.\n<\/p>\n<p>\nTime-series databases are purpose-built for this pattern. They act like a medical chart that never runs out of paper, allowing applications to look back at recent vital sign history and understand whether a wearer is moving toward an unsafe physiological state.\n<\/p>\n<h2 id=\"why-griddb-cloud-for-wearable-health-monitoring\">Why GridDB Cloud for Wearable Health Monitoring<\/h2>\n<p>\nGridDB Cloud provides an environment where sensor telemetry storage and retrieval are handled efficiently, letting the monitoring application focus entirely on health analysis rather than database infrastructure management.\n<\/p>\n<p>\nGridDB is a highly scalable, memory-first NoSQL database designed for high-frequency time-series IoT workloads. For VitalWatch, we use GridDB Cloud to:\n<\/p>\n<ol>\n<li>Store continuous wearable sensor data in <code>TIME_SERIES<\/code> containers with timestamp-based row keys.<\/li>\n<li>Maintain a fixed per-wearer schema for predictable, fast reads and writes.<\/li>\n<li>Ingest vital sign data in memory first and persist it safely to disk.<\/li>\n<li>Query recent time windows efficiently for early-warning detection.<\/li>\n<li>Correlate multiple vital sign streams in real time for chain event detection.<\/li>\n<li>Replay sensor history before an alert for physiological incident analysis.<\/li>\n<li>Provide the historical dataset that trains the machine learning health risk classifier.<\/li>\n<\/ol>\n<p><strong>Without GridDB:<\/strong><\/p>\n<ul>\n<li>Real-time multi-vital correlation would require expensive joins across separate tables.<\/li>\n<li>High-frequency wearable ingestion would create write bottlenecks.<\/li>\n<li>ML training on historical health data would require a separate ETL pipeline.<\/li>\n<\/ul>\n<h2 id=\"system-architecture\">System Architecture<\/h2>\n<p>\nVitalWatch simulates a small health monitoring scenario for three wearers \u2014 an Athlete, an Elderly Patient, and an Office Worker \u2014 enrolled in a group monitoring program. Each wearer carries a simulated smartwatch that generates Heart Rate, SpO2, Body Temperature, and Activity Level readings. Derived health metrics (estimated blood pressure and blood sugar) are computed from the raw readings before storage.\n<\/p>\n<p><img decoding=\"async\" src=\"images\/architecture.png\" alt=\"System Architecture\" \/><\/p>\n<p>\nThe overall system consists of the following main components:\n<\/p>\n<p><strong>Sensor Simulation Layer<\/strong><\/p>\n<p>\nA Python-based simulator generates realistic vital sign readings for each wearer. It applies a three-phase simulation model: Normal (all vitals safe), Stress (athlete begins showing cardiovascular signs), and Deterioration (athlete reaches critical levels while other wearers show secondary stress signals).\n<\/p>\n<p><strong>Health Estimation Layer<\/strong><\/p>\n<p>\nA rule-based estimator computes derived metrics \u2014 systolic\/diastolic blood pressure and blood glucose \u2014 from the raw sensor values. These estimates are included in every row stored in GridDB so that the dashboard and ML model have access to the full health picture.\n<\/p>\n<p><strong>Data Ingestion Layer<\/strong><\/p>\n<p>\nThe backend application receives simulated vital sign data and writes it to GridDB Cloud using the <code>multi_put<\/code> batch API, which allows rows for multiple wearer containers to be written in a single network round-trip.\n<\/p>\n<p><strong>GridDB Cloud Database<\/strong><\/p>\n<p>\nGridDB stores the complete vital sign history for each wearer in dedicated <code>TIME_SERIES<\/code> containers. The monitoring application queries this data to evaluate health conditions and detect physiological chain events.\n<\/p>\n<p><strong>Monitoring Dashboard<\/strong><\/p>\n<p>\nA web-based dashboard displays real-time vital signs, physiological chain alerts, and the fleet-wide health risk score. It polls the Flask API every three seconds and visualizes live trends using Chart.js.\n<\/p>\n<p><strong>ML Health Risk Classifier<\/strong><\/p>\n<p>\nA scikit-learn Random Forest classifier is trained directly on the historical data stored in GridDB. It learns to predict one of four health risk levels (Normal, Stress, Distress, Critical) from the seven-dimensional feature vector of each reading.\n<\/p>\n<h2 id=\"setting-up-griddb-cloud\">Setting Up GridDB Cloud<\/h2>\n<p>\nTo store wearable telemetry, a GridDB Cloud instance can be deployed through the Microsoft Azure Marketplace. After subscribing, you receive the cluster connection details including the notification provider address, cluster name, and authentication credentials.\n<\/p>\n<p>\nUsing the GridDB Python client, applications connect to the cluster through the native API. The following example shows how VitalWatch establishes a per-thread GridDB connection to avoid concurrency errors when multiple Flask worker threads are active:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">import griddb_python as griddb\r\nimport threading\r\n\r\n_local = threading.local()\r\n\r\ndef get_store():\r\n    &quot;&quot;&quot;Return a per-thread GridDB connection to avoid concurrent access errors.&quot;&quot;&quot;\r\n    if not hasattr(_local, &quot;store&quot;) or _local.store is None:\r\n        factory = griddb.StoreFactory.get_instance()\r\n        _local.store = factory.get_store(\r\n            notification_member=NOTIFICATION_MEMBER,\r\n            cluster_name=CLUSTER_NAME,\r\n            username=USERNAME,\r\n            password=PASSWORD,\r\n        )\r\n    return _local.store<\/code><\/pre>\n<\/div>\n<p>\nConnection credentials are read from environment variables so that no secrets appear in source code.\n<\/p>\n<h2 id=\"project-overview\">Project Overview<\/h2>\n<p>\nVitalWatch builds a smart health monitoring system for three simulated wearers enrolled in a group monitoring program. The system tracks each wearer&#8217;s vitals continuously and identifies early signs of physiological stress before they become critical events.\n<\/p>\n<p>\nKey ideas behind the system:\n<\/p>\n<ul>\n<li><strong>Multi-vital monitoring<\/strong>: Rather than evaluating each vital sign independently, the system looks for correlated changes that indicate a linked physiological event.<\/li>\n<li><strong>Physiological chain detection<\/strong>: It recognizes known biological relationships \u2014 for example, that falling SpO2 typically triggers compensatory heart rate elevation \u2014 and fires chain alerts when both sides of the correlation appear simultaneously.<\/li>\n<li><strong>Profile-aware thresholds<\/strong>: Each wearer has individually tuned normal ranges and alert thresholds. An athlete&#8217;s resting heart rate of 55 bpm is healthy; the same reading might warrant attention for a sedentary office worker.<\/li>\n<li><strong>Continuous risk scoring<\/strong>: Instead of a binary safe\/unsafe flag, each wearer receives a 0\u2013100 risk score that moves smoothly as vitals drift toward danger zones.<\/li>\n<\/ul>\n<h2 id=\"simulating-wearable-sensor-data\">Simulating Wearable Sensor Data<\/h2>\n<p>\nSince real wearable devices are not available, the system uses a Python sensor simulator to generate realistic vital sign streams. The simulator creates readings for three wearer profiles:\n<\/p>\n<ul>\n<li><strong>Athlete<\/strong>: Heart rate, SpO2, body temperature, activity level (trained physiology, lower resting HR)<\/li>\n<li><strong>Elderly Patient<\/strong>: Heart rate, SpO2, body temperature, activity level (lower critical thresholds, highest monitoring priority)<\/li>\n<li><strong>Office Worker<\/strong>: Heart rate, SpO2, body temperature, activity level (standard adult thresholds, sedentary baseline)<\/li>\n<\/ul>\n<p>\nTo model a realistic health event, the dataset is generated across three phases:\n<\/p>\n<ul>\n<li><strong>Normal<\/strong>: All wearers operating within their safe vital ranges.<\/li>\n<li><strong>Stress<\/strong>: The athlete begins showing cardiovascular stress \u2014 heart rate rises, SpO2 drops.<\/li>\n<li><strong>Deterioration<\/strong>: The athlete reaches critical levels; the elderly patient begins showing secondary stress; the office worker shows early signs of physiological disturbance. This models how a shared environmental trigger (extreme heat, altitude) affects multiple wearers simultaneously.<\/li>\n<\/ul>\n<p>\nTo make the simulation physically plausible rather than generating flat hardcoded values, the system uses proportional interpolation with environmental noise:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">def _interpolate(low: float, high: float, progress: float = None) -&gt; float:\r\n    &quot;&quot;&quot;Smoothly interpolate between two boundary values with optional random progress.&quot;&quot;&quot;\r\n    if progress is None:\r\n        progress = random.uniform(0.0, 1.0)\r\n    return low + progress * (high - low)\r\n\r\ndef generate_reading(wearer_id, status=&quot;Normal&quot;, progress=0.0, timestamp=None):\r\n    nrm = WEARERS[wearer_id][&quot;normal&quot;]\r\n    thr = WEARERS[wearer_id][&quot;thresholds&quot;]\r\n\r\n    if status == &quot;Stress&quot;:\r\n        # HR ramps upward; SpO2 begins to drop (inverted: lower = worse)\r\n        hr_base   = _interpolate(nrm[&quot;heart_rate&quot;][1], thr[&quot;heart_rate&quot;][&quot;warning&quot;], progress)\r\n        spo2_base = _interpolate(nrm[&quot;spo2&quot;][0], thr[&quot;spo2&quot;][&quot;warning&quot;], progress)\r\n        t_base    = _interpolate(nrm[&quot;temperature&quot;][1], thr[&quot;temperature&quot;][&quot;warning&quot;], progress * 0.6)\r\n\r\n    # Environmental noise added to every reading regardless of phase\r\n    noise_hr   = random.uniform(-2.0, 2.0)\r\n    noise_spo2 = random.uniform(-0.3, 0.3)\r\n    noise_temp = random.uniform(-0.1, 0.1)<\/code><\/pre>\n<\/div>\n<p>\nThis approach ensures that simulated vitals drift naturally toward thresholds rather than jumping abruptly, making the dashboard transitions visually and physiologically meaningful.\n<\/p>\n<h2 id=\"health-metric-estimation\">Health Metric Estimation<\/h2>\n<p>\nOne of VitalWatch&#8217;s key additions is a rule-based health estimator that derives secondary health metrics from the raw wearable sensor data. Since wearable devices primarily measure heart rate, SpO2, temperature, and motion, higher-order metrics like blood pressure and blood glucose must be inferred.\n<\/p>\n<p>\nThe estimations use simplified physiological relationships that are deliberately documented as approximations:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">def estimate_systolic_bp(heart_rate: float, spo2: float, activity_level: float) -&gt; float:\r\n    &quot;&quot;&quot;\r\n    Estimate systolic blood pressure (mmHg) from HR, SpO2, and activity.\r\n    NOTE: Simplified demonstration formula \u2014 not clinically accurate.\r\n    &quot;&quot;&quot;\r\n    baseline     = 120.0\r\n    hr_delta     = (heart_rate - 72) * 0.50    # HR deviation from resting reference\r\n    activity_adj = (activity_level \/ 10.0) * 4.0\r\n    spo2_stress  = max(0.0, (96.0 - spo2) * 0.80)  # hypoxic stress contribution\r\n    noise        = random.uniform(-3.0, 3.0)\r\n    return round(baseline + hr_delta + activity_adj + spo2_stress + noise, 1)\r\n\r\n\r\ndef estimate_blood_sugar(heart_rate: float, activity_level: float, spo2: float) -&gt; float:\r\n    &quot;&quot;&quot;\r\n    Estimate blood glucose (mg\/dL) from HR, activity, and SpO2.\r\n    NOTE: Simplified demonstration formula \u2014 not clinically accurate.\r\n    &quot;&quot;&quot;\r\n    baseline     = 90.0\r\n    hr_delta     = (heart_rate - 70) * 0.30\r\n    activity_adj = activity_level * 0.40\r\n    spo2_stress  = max(0.0, (96.0 - spo2) * 1.50)\r\n    noise        = random.uniform(-5.0, 5.0)\r\n    return round(baseline + hr_delta + activity_adj + spo2_stress + noise, 1)<\/code><\/pre>\n<\/div>\n<p>\nA single <code>derive_health_metrics()<\/code> function acts as the entry point used by the sensor simulator so that every row stored in GridDB automatically includes the full estimated health picture:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">def derive_health_metrics(heart_rate, spo2, temperature, activity_level) -&gt; dict:\r\n    &quot;&quot;&quot;Given raw vitals, return all derived health metric estimates.&quot;&quot;&quot;\r\n    return {\r\n        &quot;systolic_bp&quot;:  estimate_systolic_bp(heart_rate, spo2, activity_level),\r\n        &quot;diastolic_bp&quot;: estimate_diastolic_bp(heart_rate, activity_level),\r\n        &quot;blood_sugar&quot;:  estimate_blood_sugar(heart_rate, activity_level, spo2),\r\n    }<\/code><\/pre>\n<\/div>\n<h2 id=\"live-alert-simulation\">Live Alert Simulation<\/h2>\n<p>\nTo demonstrate how a health deterioration event develops over time, the project includes a live alert simulation script. Rather than inserting a static pre-built dataset, the script gradually writes escalating vital sign readings into GridDB Cloud every second, mimicking how a real health event would evolve.\n<\/p>\n<p>\nThe simulation follows three stages:\n<\/p>\n<ul>\n<li><strong>Normal Baseline<\/strong> \u2013 All wearers within safe ranges for the first few seconds.<\/li>\n<li><strong>Athlete Stress<\/strong> \u2013 The athlete&#8217;s heart rate climbs and SpO2 begins to drop, proportionally ramped using interpolation.<\/li>\n<li><strong>Full Deterioration<\/strong> \u2013 The athlete reaches critical levels; the elderly patient shows secondary stress; the office worker starts showing early disturbance signals.<\/li>\n<\/ul>\n<p>\nA simplified view of the simulation loop is shown below:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">def trigger_alert():\r\n    &quot;&quot;&quot;Simulates a live health event that persists until resolved on the dashboard.&quot;&quot;&quot;\r\n    store = insert_data.get_gridstore()\r\n    start_sim()   # signals the Flask API that simulation is active\r\n\r\n    i = 0\r\n    while is_sim_active():\r\n        ts    = datetime.now(timezone.utc)\r\n        batch = {}\r\n\r\n        for wearer_id in WEARERS:\r\n            # Determine target health state based on simulation phase\r\n            target = determine_phase(i, wearer_id)\r\n            row    = make_row(ts, wearer_id, target)\r\n            batch[WEARERS[wearer_id][&quot;container&quot;]] = [row]\r\n\r\n        store.multi_put(batch)\r\n        i += 1\r\n        time.sleep(1)<\/code><\/pre>\n<\/div>\n<p>\nWhen the dashboard operator clicks <strong>&#8220;Alert Addressed&#8221;<\/strong>, the Flask API clears the simulation flag. The script detects this, injects a final batch of normal-range readings into GridDB Cloud, and exits. Those healthy readings immediately restore the dashboard to a stable state without requiring a manual reset.\n<\/p>\n<h2 id=\"storing-health-data-in-griddb-cloud\">Storing Health Data in GridDB Cloud<\/h2>\n<p>\nAfter generating the simulated vital sign readings, the data is stored in GridDB Cloud so the monitoring system can access recent history. Each wearer is assigned their own <code>TIME_SERIES<\/code> container with a fixed schema that stores all raw and derived health metrics.\n<\/p>\n<p>\nThe timestamp acts as the primary key, allowing efficient time-ordered storage and retrieval of each wearer&#8217;s health history.\n<\/p>\n<p><strong>Creating a <code>TIME_SERIES<\/code> container per wearer:<\/strong><\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">def setup_containers(store) -&gt; dict:\r\n    &quot;&quot;&quot;Create one TIME_SERIES container per wearer profile.&quot;&quot;&quot;\r\n    containers = {}\r\n    for wearer_id, cfg in WEARERS.items():\r\n        con_info = griddb.ContainerInfo(\r\n            cfg[&quot;container&quot;],\r\n            [\r\n                [&quot;timestamp&quot;,      griddb.Type.TIMESTAMP],\r\n                [&quot;heart_rate&quot;,     griddb.Type.DOUBLE],\r\n                [&quot;spo2&quot;,           griddb.Type.DOUBLE],\r\n                [&quot;temperature&quot;,    griddb.Type.DOUBLE],\r\n                [&quot;activity_level&quot;, griddb.Type.DOUBLE],\r\n                [&quot;systolic_bp&quot;,    griddb.Type.DOUBLE],   # estimated\r\n                [&quot;diastolic_bp&quot;,   griddb.Type.DOUBLE],   # estimated\r\n                [&quot;blood_sugar&quot;,    griddb.Type.DOUBLE],   # estimated\r\n            ],\r\n            griddb.ContainerType.TIME_SERIES,\r\n        )\r\n        containers[wearer_id] = store.put_container(con_info)\r\n    return containers<\/code><\/pre>\n<\/div>\n<p><strong>Inserting a full dataset using <code>multi_put<\/code>:<\/strong><\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">def insert_dataset(store, dataset: dict) -&gt; None:\r\n    &quot;&quot;&quot;Bulk-insert all wearer readings in a single multi_put call.&quot;&quot;&quot;\r\n    batch = {}\r\n    for wearer_id, readings in dataset.items():\r\n        container_name = WEARERS[wearer_id][&quot;container&quot;]\r\n        rows = []\r\n        for r in readings:\r\n            ts = datetime.fromisoformat(r[&quot;timestamp&quot;].replace(&quot;Z&quot;, &quot;+00:00&quot;))\r\n            rows.append([ts, r[&quot;heart_rate&quot;], r[&quot;spo2&quot;], r[&quot;temperature&quot;],\r\n                         r[&quot;activity_level&quot;], r[&quot;systolic_bp&quot;], r[&quot;diastolic_bp&quot;],\r\n                         r[&quot;blood_sugar&quot;]])\r\n        batch[container_name] = rows\r\n\r\n    store.multi_put(batch)<\/code><\/pre>\n<\/div>\n<p>\nThe <code>multi_put<\/code> operation writes rows for all three wearer containers in a single request, significantly improving ingestion efficiency when handling continuous vital sign streams.\n<\/p>\n<h2 id=\"querying-health-data-and-detecting-pre-alert-conditions\">Querying Health Data and Detecting Pre-Alert Conditions<\/h2>\n<p>\nOnce vital sign data is stored in GridDB Cloud, the monitoring system queries recent readings to evaluate each wearer&#8217;s health condition. The system retrieves the latest records from each wearer container using GridDB&#8217;s Time-Series Query Language (TQL).\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">def query_recent(store, wearer_id: str, limit: int = 20) -&gt; list:\r\n    &quot;&quot;&quot;Fetch the most recent readings for a wearer using GridDB TQL.&quot;&quot;&quot;\r\n    container = store.get_container(WEARERS[wearer_id][&quot;container&quot;])\r\n\r\n    query = container.query(f&quot;select * order by timestamp desc limit {limit}&quot;)\r\n    rs    = query.fetch()\r\n\r\n    readings = []\r\n    while rs.has_next():\r\n        row = rs.next()\r\n        readings.append({\r\n            &quot;timestamp&quot;:      row[0].isoformat(),\r\n            &quot;heart_rate&quot;:     row[1],\r\n            &quot;spo2&quot;:           row[2],\r\n            &quot;temperature&quot;:    row[3],\r\n            &quot;activity_level&quot;: row[4],\r\n            &quot;systolic_bp&quot;:    row[5],\r\n            &quot;diastolic_bp&quot;:   row[6],\r\n            &quot;blood_sugar&quot;:    row[7],\r\n        })\r\n    return readings<\/code><\/pre>\n<\/div>\n<p>\nTo avoid false alerts caused by momentary sensor spikes, the system evaluates health conditions using a rolling window of the three most recent readings. By averaging the latest values, the monitoring logic becomes stable and resistant to transient noise:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">window   = readings[:3]\r\navg_hr   = sum(r[&quot;heart_rate&quot;]     for r in window) \/ len(window)\r\navg_spo2 = sum(r[&quot;spo2&quot;]           for r in window) \/ len(window)\r\navg_temp = sum(r[&quot;temperature&quot;]    for r in window) \/ len(window)\r\navg_act  = sum(r[&quot;activity_level&quot;] for r in window) \/ len(window)<\/code><\/pre>\n<\/div>\n<p>\nA key implementation detail is the handling of SpO2 as an <strong>inverted vital<\/strong>: unlike heart rate or temperature where higher values indicate danger, a <em>lower<\/em> SpO2 value indicates physiological risk. The severity function handles both directions using an <code>inverted<\/code> flag in the threshold configuration:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">def vital_severity(value: float, vital_key: str, wearer_id: str) -&gt; float:\r\n    &quot;&quot;&quot;Return a 0.0\u20131.5 severity score. Handles both normal and inverted vitals.&quot;&quot;&quot;\r\n    thr      = WEARERS[wearer_id][&quot;thresholds&quot;][vital_key]\r\n    inverted = thr.get(&quot;inverted&quot;, False)\r\n\r\n    if inverted:\r\n        # SpO2: lower value = higher severity\r\n        normal_safe = WEARERS[wearer_id][&quot;normal&quot;][vital_key][0]\r\n        if value &gt;= normal_safe:              return 0.0\r\n        elif value &gt;= thr[&quot;warning&quot;]:         return 0.30 * (normal_safe - value) \/ (normal_safe - thr[&quot;warning&quot;])\r\n        elif value &gt;= thr[&quot;critical&quot;]:        return 0.30 + 0.70 * (thr[&quot;warning&quot;] - value) \/ (thr[&quot;warning&quot;] - thr[&quot;critical&quot;])\r\n        else:\r\n            overshoot = (thr[&quot;critical&quot;] - value) \/ max(thr[&quot;warning&quot;] - thr[&quot;critical&quot;], 0.1)\r\n            return min(1.0 + overshoot * 0.5, 1.50)\r\n    else:\r\n        # HR, temperature, activity: higher value = higher severity\r\n        ...<\/code><\/pre>\n<\/div>\n<h2 id=\"risk-scoring\">Risk Scoring<\/h2>\n<p>\nInstead of a simple status label, each wearer receives a continuous risk score between 0 and 100 based on exactly how far their vital signs have drifted from their individual safe ranges.\n<\/p>\n<p>\nFor example, an athlete with a heart rate of 160 bpm and an elderly patient both showing the same reading would receive very different risk scores, because their normal ranges and thresholds are configured independently.\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">def wearer_risk_score(wearer_id, avg_hr, avg_spo2, avg_temp, avg_act) -&gt; int:\r\n    &quot;&quot;&quot;Calculate a 0\u2013100 health risk score using weighted vital severities.&quot;&quot;&quot;\r\n    s_hr   = vital_severity(avg_hr,   &quot;heart_rate&quot;,     wearer_id)\r\n    s_spo2 = vital_severity(avg_spo2, &quot;spo2&quot;,           wearer_id)\r\n    s_temp = vital_severity(avg_temp, &quot;temperature&quot;,    wearer_id)\r\n    s_act  = vital_severity(avg_act,  &quot;activity_level&quot;, wearer_id)\r\n\r\n    weighted = (\r\n        s_hr   * VITAL_WEIGHTS[&quot;heart_rate&quot;]     +   # 35%\r\n        s_spo2 * VITAL_WEIGHTS[&quot;spo2&quot;]           +   # 40%  \u2190 SpO2 carries most weight\r\n        s_temp * VITAL_WEIGHTS[&quot;temperature&quot;]    +   # 15%\r\n        s_act  * VITAL_WEIGHTS[&quot;activity_level&quot;]     # 10%\r\n    )\r\n    return min(round(weighted * 100), 100)<\/code><\/pre>\n<\/div>\n<p>\nThe fleet-wide risk score is a weighted average across all wearers \u2014 the elderly patient contributes 50% of the weight because they are the highest-priority monitoring subject. Active physiological chain events add extra penalty points on top.\n<\/p>\n<h2 id=\"physiological-chain-detection\">Physiological Chain Detection<\/h2>\n<p>\nVitalWatch understands that vital signs are physiologically linked. A falling SpO2 causes the cardiovascular system to compensate by increasing heart rate. Sustained high heart rate generates excess metabolic heat, raising body temperature. These relationships are encoded as rules:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">VITAL_CHAIN_RULES = [\r\n    {\r\n        &quot;source&quot;: &quot;spo2&quot;,\r\n        &quot;target&quot;: &quot;heart_rate&quot;,\r\n        &quot;message&quot;: (\r\n            &quot;Oxygen-Cardiac Chain: Falling SpO2 is driving compensatory heart rate elevation. &quot;\r\n            &quot;The body is increasing cardiac output to offset reduced blood oxygen.&quot;\r\n        ),\r\n    },\r\n    {\r\n        &quot;source&quot;: &quot;heart_rate&quot;,\r\n        &quot;target&quot;: &quot;temperature&quot;,\r\n        &quot;message&quot;: (\r\n            &quot;Cardiac-Thermal Chain: Elevated heart rate is correlating with rising body temperature. &quot;\r\n            &quot;Increased metabolic activity is generating excess heat.&quot;\r\n        ),\r\n    },\r\n    {\r\n        &quot;source&quot;: &quot;spo2&quot;,\r\n        &quot;target&quot;: &quot;temperature&quot;,\r\n        &quot;message&quot;: (\r\n            &quot;Full Physiological Chain: Simultaneous SpO2 desaturation and thermal elevation detected. &quot;\r\n            &quot;This pattern may indicate acute physiological stress or systemic illness.&quot;\r\n        ),\r\n    },\r\n]<\/code><\/pre>\n<\/div>\n<p>\nThe chain detection function evaluates each wearer&#8217;s per-vital statuses against these rules. A chain alert fires only when the source vital is in a danger state <em>and<\/em> the target vital also shows an at-risk reading \u2014 confirming a linked physiological event rather than an isolated measurement anomaly:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">def detect_health_chains(wearer_id: str, vital_statuses: dict) -&gt; list:\r\n    chains      = []\r\n    danger      = {&quot;Distress&quot;, &quot;Critical&quot;}\r\n    at_risk     = {&quot;Stress&quot;, &quot;Distress&quot;, &quot;Critical&quot;}\r\n\r\n    for rule in VITAL_CHAIN_RULES:\r\n        src = vital_statuses.get(rule[&quot;source&quot;], &quot;Normal&quot;)\r\n        tgt = vital_statuses.get(rule[&quot;target&quot;], &quot;Normal&quot;)\r\n        if src in danger and tgt in at_risk:\r\n            chains.append({\r\n                &quot;wearer_id&quot;: wearer_id,\r\n                &quot;source&quot;:    rule[&quot;source&quot;],\r\n                &quot;target&quot;:    rule[&quot;target&quot;],\r\n                &quot;message&quot;:   rule[&quot;message&quot;],\r\n            })\r\n    return chains<\/code><\/pre>\n<\/div>\n<h2 id=\"machine-learning-health-risk-classifier\">Machine Learning Health Risk Classifier<\/h2>\n<p>\nVitalWatch includes a complete machine learning pipeline that uses the historical data stored in GridDB to train a health risk classifier. The model learns to predict one of four health states \u2014 Normal, Stress, Distress, or Critical \u2014 from the seven-dimensional feature vector of a single wearable reading.\n<\/p>\n<p><strong>Why Random Forest?<\/strong><\/p>\n<p>\nRandom Forest is an ideal fit for this task because it seamlessly handles mixed physiological features across different units without requiring normalization. It also remains highly robust even with the smaller datasets typical of wearable monitoring demos. Additionally, the model outputs clear feature importances, making its health risk predictions easily explainable.\n<\/p>\n<p><strong>Loading data from GridDB<\/strong><\/p>\n<p>\nThe training pipeline loads all available readings directly from the GridDB containers:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">def load_training_data(store) -&gt; tuple:\r\n    &quot;&quot;&quot;Query all readings from GridDB and build a feature matrix with auto-generated labels.&quot;&quot;&quot;\r\n    X, y, wearer_labels = [], [], []\r\n\r\n    for wearer_id in WEARERS:\r\n        readings = query_recent(store, wearer_id, limit=500)\r\n\r\n        for r in readings:\r\n            features = [r[&quot;heart_rate&quot;], r[&quot;spo2&quot;], r[&quot;temperature&quot;],\r\n                        r[&quot;activity_level&quot;], r[&quot;systolic_bp&quot;],\r\n                        r[&quot;diastolic_bp&quot;], r[&quot;blood_sugar&quot;]]\r\n            # Labels are generated using the same rule-based logic as the dashboard\r\n            label = STATUS_TO_INT[analyze_wearer(wearer_id, [r])[&quot;status&quot;]]\r\n            X.append(features)\r\n            y.append(label)\r\n\r\n    return np.array(X), np.array(y), wearer_labels<\/code><\/pre>\n<\/div>\n<p>\nThis approach makes labels consistent with the dashboard display: the ML model learns to replicate the same health risk judgments that the rule-based monitoring system makes, but as a learnable function of the raw feature values.\n<\/p>\n<p><strong>Training and evaluation<\/strong><\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-python\">model = RandomForestClassifier(\r\n    n_estimators=150,\r\n    max_depth=10,\r\n    min_samples_leaf=2,\r\n    random_state=42,\r\n    n_jobs=-1,\r\n)\r\nmodel.fit(X_train, y_train)<\/code><\/pre>\n<\/div>\n<p>\nAfter training, the pipeline prints a classification report and confusion matrix, followed by ranked feature importances:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-plaintext\">  Feature Importances:\r\n                  spo2  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588  0.3912\r\n            heart_rate  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588          0.3104\r\n           systolic_bp  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588                              0.1187\r\n           blood_sugar  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588                                  0.0823\r\n           temperature  \u2588\u2588\u2588\u2588\u2588                                     0.0521\r\n          diastolic_bp  \u2588\u2588\u2588\u2588                                      0.0401\r\n        activity_level  \u2588\u2588                                        0.0052<\/code><\/pre>\n<\/div>\n<p>\nSpO2 and heart rate emerge as the most predictive features \u2014 a result that aligns with the physiological chain rules encoded in the rule-based detection layer.\n<\/p>\n<h2 id=\"building-the-monitoring-dashboard\">Building the Monitoring Dashboard<\/h2>\n<p><a href=\"\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png\"><img fetchpriority=\"high\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png\" alt=\"\" width=\"1920\" height=\"1080\" class=\"aligncenter size-full wp-image-55451\" srcset=\"\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png 1920w, \/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546-300x169.png 300w, \/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546-1024x576.png 1024w, \/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546-768x432.png 768w, \/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546-1536x864.png 1536w, \/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546-150x85.png 150w, \/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546-600x338.png 600w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>\nVisualization is essential for making vital sign data actionable. The VitalWatch dashboard was built using HTML, JavaScript, and Chart.js to display real-time wearer status, vital sign trend charts, physiological chain alerts, and the fleet-wide health risk score.\n<\/p>\n<p>\nThe Flask backend exposes three main data API endpoints that the dashboard polls every three seconds:\n<\/p>\n<table class=\"markdown-table\" style=\"border-collapse: collapse; width: 100%; margin: 1em 0;\">\n<thead>\n<tr>\n<th style=\"border: 1px solid #ddd; padding: 8px; background-color: #f2f2f2; text-align: left;\">Endpoint<\/th>\n<th style=\"border: 1px solid #ddd; padding: 8px; background-color: #f2f2f2; text-align: left;\">What it returns<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\"><code>GET \/api\/fleet<\/code><\/td>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\">(Main) Status of all wearers + chain alerts + risk score<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\"><code>GET \/api\/wearer\/<id><\/code><\/td>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\">Vital sign history for a single wearer (used for charts)<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\"><code>GET \/api\/timeline<\/code><\/td>\n<td style=\"border: 1px solid #ddd; padding: 8px; text-align: left;\">Log of health status transitions over time<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\nA simplified view of the dashboard polling function:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">async function pollFleet() {\r\n  try {\r\n    const res  = await fetch(&#x27;\/api\/fleet&#x27;);\r\n    const data = await res.json();\r\n\r\n    \/\/ Update each wearer card\r\n    for (const [wearerId, status] of Object.entries(data.wearers)) {\r\n      setCard(wearerId, status.status, status.message, status.latest);\r\n    }\r\n\r\n    renderChains(data.chains || []);\r\n    updateFleetScore(data.risk_score ?? 0);\r\n\r\n  } catch (e) {\r\n    console.error(&#x27;Fleet poll failed:&#x27;, e);\r\n  }\r\n}<\/code><\/pre>\n<\/div>\n<p>\nThe dashboard calls the fleet endpoint every three seconds to keep the interface synchronized with the latest health data in GridDB Cloud. The chart endpoint provides rolling vital sign history for each wearer, rendered as a dual-axis mini trend chart (HR on the left axis, SpO2 on the right).\n<\/p>\n<h2 id=\"running-the-project\">Running the Project<\/h2>\n<p>\nMake sure GridDB Cloud is running and credentials are configured as environment variables. Then run the following in order:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\"># Step 1: Create containers and seed historical data\r\n$ $ python src\/insert_data.py\r\n\r\n# Step 2: Start the monitoring backend\r\n$ $ python src\/app.py\r\n\r\n# Step 3 (optional): Keep the dashboard alive with a live heartbeat\r\n$ $ python src\/insert_data.py --live\r\n\r\n# Step 4 (optional): Trigger a live alert simulation\r\n$ $ python src\/simulate_alert.py\r\n\r\n# Step 5 (optional): Train the ML health risk classifier\r\n$ $ python src\/train_model.py<\/code><\/pre>\n<\/div>\n<p>\nOpen <code>http:\/\/localhost:5000<\/code> to view the dashboard.\n<\/p>\n<p><strong>The Background Heartbeat (<code>insert_data.py --live<\/code>)<\/strong>: This script provides a stable, healthy baseline so the dashboard stays &#8220;green&#8221; by default.<\/p>\n<p><strong>The Manual Alert (<code>simulate_alert.py<\/code>)<\/strong>: This script temporarily introduces a deteriorating health event to show how vital signs cascade. Click <strong>&#8220;Alert Addressed&#8221;<\/strong> in the dashboard to resolve it.<\/p>\n<p>\nOne of the advantages of using GridDB for this architecture is automatic recovery: once the simulation finishes, the background producer continues sending normal-range readings. These healthy readings naturally displace the temporary critical spikes in the rolling query window, and the system returns to a safe state without a manual database reset.\n<\/p>\n<h2 id=\"results-and-dashboard-overview\">Results and Dashboard Overview<\/h2>\n<p>\nAfter running the system, the monitoring dashboard displays the real-time health status of all three wearers. The interface shows live vital signs for Heart Rate, SpO2, Body Temperature, and Activity Level for each wearer, along with trend charts, chain alert panels, and the fleet-wide risk score.\n<\/p>\n<p><strong>Normal State<\/strong><\/p>\n<p>\nIn the normal state, all wearers show green status indicators and a fleet risk score near 0. The escalation timeline panel is empty, confirming no status transitions have occurred.\n<\/p>\n<p><img decoding=\"async\" src=\"images\/normal_state.png\" alt=\"Normal State\" \/><\/p>\n<p><strong>Stress Detected<\/strong><\/p>\n<p>\nAs the athlete&#8217;s heart rate climbs and SpO2 begins to fall, individual vital signs transition to warning state. The athlete card updates to &#8220;Stress&#8221; and the overall risk score begins rising.\n<\/p>\n<p><img decoding=\"async\" src=\"images\/stress_state.png\" alt=\"Stress State\" \/><\/p>\n<p><strong>Physiological Chains Active<\/strong><\/p>\n<p>\nWhen the athlete&#8217;s SpO2 drops into the danger zone while heart rate is simultaneously elevated, the system fires a chain alert: &#8220;Oxygen-Cardiac Chain: Falling SpO2 is driving compensatory heart rate elevation.&#8221; A second chain may fire if body temperature also begins rising.\n<\/p>\n<p><img decoding=\"async\" src=\"images\/chain_active.png\" alt=\"Chain Alerts\" \/><\/p>\n<p><strong>Alert Resolved<\/strong><\/p>\n<p>\nOnce the operator clicks &#8220;Alert Addressed,&#8221; the simulation stops, recovery readings are injected, and the dashboard returns to normal. The risk score drops back toward zero and chain alerts clear.\n<\/p>\n<p><img decoding=\"async\" src=\"images\/alert_resolved.png\" alt=\"Alert Resolved\" \/><\/p>\n<p>\nBy visualizing vital sign trends, physiological chain events, and fleet risk levels together, the dashboard gives health monitoring operators a clear and actionable picture of wearer health states.\n<\/p>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>\nWearable health monitoring generates high-frequency, time-ordered data that tells a much richer story than any single sensor reading. Detecting that story requires a database purpose-built for time-series workloads and an analysis layer that understands physiological correlations rather than evaluating each vital in isolation.\n<\/p>\n<p>\nIn this project, we built VitalWatch \u2014 a complete wearable health monitoring prototype using GridDB Cloud to store and query vital sign telemetry. By combining simulated sensor readings with rule-based physiological chain detection and a machine learning health risk classifier, the system can detect early warning patterns before they escalate into critical events.\n<\/p>\n<p>\nThe complete implementation can be found in the project repository. :<br \/>\nhttps:\/\/github.com\/DoneByManthan\/GridDB-VitalWatch.git\n<\/p>\n<p>\nIn the future, this approach could be extended with:\n<\/p>\n<ul>\n<li><strong>Personalized ML models<\/strong> trained on each wearer&#8217;s individual baseline rather than group averages stored in GridDB.<\/li>\n<li><strong>Anomaly detection<\/strong> using unsupervised methods (e.g., Isolation Forest) on the GridDB historical data to catch unusual patterns that fall outside rule-defined thresholds.<\/li>\n<li><strong>Real device integration<\/strong> by replacing the Python simulator with a Bluetooth LE or MQTT data ingestion layer that receives readings directly from consumer wearables.<\/li>\n<li><strong>Federated learning<\/strong> where each wearer&#8217;s device trains a local model on-device and only sends model weight updates to a central server, preserving health data privacy while improving the global classifier.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>> Medical Disclaimer: All health metric estimations in this project (blood pressure, blood sugar) are simplified rule-based simulations for demonstration and educational purposes only. They are not clinically accurate and should never be used for real medical decision-making. This blog is the longer version of the hackathon entry from VitalWatch. You can see their original [&hellip;]<\/p>\n","protected":false},"author":41,"featured_media":55451,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[121],"tags":[],"class_list":["post-55448","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>VitalWatch: Real-Time Wearable Health Monitoring with GridDB Cloud | GridDB: Open Source Time Series Database for IoT<\/title>\n<meta name=\"description\" content=\"&gt; Medical Disclaimer: All health metric estimations in this project (blood pressure, blood sugar) are simplified rule-based simulations for demonstration\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"VitalWatch: Real-Time Wearable Health Monitoring with GridDB Cloud | GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"og:description\" content=\"&gt; Medical Disclaimer: All health metric estimations in this project (blood pressure, blood sugar) are simplified rule-based simulations for demonstration\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/\" \/>\n<meta property=\"og:site_name\" content=\"GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/griddbcommunity\/\" \/>\n<meta property=\"article:published_time\" content=\"2026-07-18T22:14:52+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-07-22T22:31:29+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.griddb.net\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"griddb-admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:site\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"griddb-admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"14 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/\"},\"author\":{\"name\":\"griddb-admin\",\"@id\":\"https:\/\/www.griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\"},\"headline\":\"VitalWatch: Real-Time Wearable Health Monitoring with GridDB Cloud\",\"datePublished\":\"2026-07-18T22:14:52+00:00\",\"dateModified\":\"2026-07-22T22:31:29+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/\"},\"wordCount\":2872,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.griddb.net\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png\",\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/\",\"url\":\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/\",\"name\":\"VitalWatch: Real-Time Wearable Health Monitoring with GridDB Cloud | GridDB: Open Source Time Series Database for IoT\",\"isPartOf\":{\"@id\":\"https:\/\/www.griddb.net\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png\",\"datePublished\":\"2026-07-18T22:14:52+00:00\",\"dateModified\":\"2026-07-22T22:31:29+00:00\",\"description\":\"> Medical Disclaimer: All health metric estimations in this project (blood pressure, blood sugar) are simplified rule-based simulations for demonstration\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/#primaryimage\",\"url\":\"\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png\",\"contentUrl\":\"\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png\",\"width\":1920,\"height\":1080},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.griddb.net\/en\/#website\",\"url\":\"https:\/\/www.griddb.net\/en\/\",\"name\":\"GridDB: Open Source Time Series Database for IoT\",\"description\":\"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL\",\"publisher\":{\"@id\":\"https:\/\/www.griddb.net\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.griddb.net\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.griddb.net\/en\/#organization\",\"name\":\"Fixstars\",\"url\":\"https:\/\/www.griddb.net\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.griddb.net\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"contentUrl\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"width\":200,\"height\":83,\"caption\":\"Fixstars\"},\"image\":{\"@id\":\"https:\/\/www.griddb.net\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/griddbcommunity\/\",\"https:\/\/x.com\/GridDBCommunity\",\"https:\/\/www.linkedin.com\/company\/griddb-by-toshiba\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\",\"name\":\"griddb-admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.griddb.net\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"caption\":\"griddb-admin\"},\"url\":\"https:\/\/www.griddb.net\/en\/author\/griddb-admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"VitalWatch: Real-Time Wearable Health Monitoring with GridDB Cloud | GridDB: Open Source Time Series Database for IoT","description":"> Medical Disclaimer: All health metric estimations in this project (blood pressure, blood sugar) are simplified rule-based simulations for demonstration","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/","og_locale":"en_US","og_type":"article","og_title":"VitalWatch: Real-Time Wearable Health Monitoring with GridDB Cloud | GridDB: Open Source Time Series Database for IoT","og_description":"> Medical Disclaimer: All health metric estimations in this project (blood pressure, blood sugar) are simplified rule-based simulations for demonstration","og_url":"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/","og_site_name":"GridDB: Open Source Time Series Database for IoT","article_publisher":"https:\/\/www.facebook.com\/griddbcommunity\/","article_published_time":"2026-07-18T22:14:52+00:00","article_modified_time":"2026-07-22T22:31:29+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/www.griddb.net\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png","type":"image\/png"}],"author":"griddb-admin","twitter_card":"summary_large_image","twitter_creator":"@GridDBCommunity","twitter_site":"@GridDBCommunity","twitter_misc":{"Written by":"griddb-admin","Est. reading time":"14 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/#article","isPartOf":{"@id":"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/"},"author":{"name":"griddb-admin","@id":"https:\/\/www.griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233"},"headline":"VitalWatch: Real-Time Wearable Health Monitoring with GridDB Cloud","datePublished":"2026-07-18T22:14:52+00:00","dateModified":"2026-07-22T22:31:29+00:00","mainEntityOfPage":{"@id":"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/"},"wordCount":2872,"commentCount":0,"publisher":{"@id":"https:\/\/www.griddb.net\/en\/#organization"},"image":{"@id":"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png","articleSection":["Blog"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/","url":"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/","name":"VitalWatch: Real-Time Wearable Health Monitoring with GridDB Cloud | GridDB: Open Source Time Series Database for IoT","isPartOf":{"@id":"https:\/\/www.griddb.net\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/#primaryimage"},"image":{"@id":"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png","datePublished":"2026-07-18T22:14:52+00:00","dateModified":"2026-07-22T22:31:29+00:00","description":"> Medical Disclaimer: All health metric estimations in this project (blood pressure, blood sugar) are simplified rule-based simulations for demonstration","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.griddb.net\/en\/blog\/vitalwatch-real-time-wearable-health-monitoring-with-griddb-cloud\/#primaryimage","url":"\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png","contentUrl":"\/wp-content\/uploads\/2026\/07\/Screenshot-2026-06-22-210546.png","width":1920,"height":1080},{"@type":"WebSite","@id":"https:\/\/www.griddb.net\/en\/#website","url":"https:\/\/www.griddb.net\/en\/","name":"GridDB: Open Source Time Series Database for IoT","description":"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL","publisher":{"@id":"https:\/\/www.griddb.net\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.griddb.net\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.griddb.net\/en\/#organization","name":"Fixstars","url":"https:\/\/www.griddb.net\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.griddb.net\/en\/#\/schema\/logo\/image\/","url":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","contentUrl":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","width":200,"height":83,"caption":"Fixstars"},"image":{"@id":"https:\/\/www.griddb.net\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/griddbcommunity\/","https:\/\/x.com\/GridDBCommunity","https:\/\/www.linkedin.com\/company\/griddb-by-toshiba"]},{"@type":"Person","@id":"https:\/\/www.griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233","name":"griddb-admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.griddb.net\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","caption":"griddb-admin"},"url":"https:\/\/www.griddb.net\/en\/author\/griddb-admin\/"}]}},"_links":{"self":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts\/55448","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/comments?post=55448"}],"version-history":[{"count":3,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts\/55448\/revisions"}],"predecessor-version":[{"id":55453,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts\/55448\/revisions\/55453"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/media\/55451"}],"wp:attachment":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/media?parent=55448"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/categories?post=55448"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/tags?post=55448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}