DEV Community

Cover image for Designing Room-Level Location Logic for a Hospital RTLS
Suraj Informatics
Suraj Informatics

Posted on Originally published at surajinformatics.com

Designing Room-Level Location Logic for a Hospital RTLS

BLE beacons and RFID readers in a hospital do not tell you "the pump is in room 304". They tell you that tag A1F3 was heard by receiver R-3-07 at -71 dBm. Turning that stream into a reliable room-level location is the core software problem in any hospital RTLS.

The raw data

from dataclasses import dataclass
from datetime import datetime

@dataclass
class Sighting:
    tag_id: str        # tag on the device
    receiver_id: str   # fixed receiver, mapped to a room or zone
    rssi: int          # signal strength in dBm
    ts: datetime
Enter fullscreen mode Exit fullscreen mode

Step 1: smooth the noise

RSSI jumps around as people walk past and doors open. Never decide location from a single reading. Keep a short window per tag and receiver and use the median:

from statistics import median
from collections import defaultdict, deque

WINDOW = 5
buf = defaultdict(lambda: deque(maxlen=WINDOW))

def add(s: Sighting):
    buf[(s.tag_id, s.receiver_id)].append(s.rssi)

def strength(tag, receiver):
    vals = buf[(tag, receiver)]
    return median(vals) if vals else None
Enter fullscreen mode Exit fullscreen mode

Step 2: pick a room, with hysteresis

Choose the receiver with the strongest smoothed signal, but only move the device to a new room if the new room wins by a margin for a few cycles. Without this, a pump near a wall will "flicker" between two rooms all day.

MARGIN = 6   # dB the new room must win by
CONFIRM = 3  # consecutive cycles

def decide(current_room, candidates, streak):
    best_room, best = max(candidates.items(), key=lambda kv: kv[1])
    if best_room == current_room:
        return current_room, 0
    if best - candidates.get(current_room, -200) >= MARGIN:
        streak += 1
        if streak >= CONFIRM:
            return best_room, 0
    return current_room, streak
Enter fullscreen mode Exit fullscreen mode

Step 3: handle silence

Tags go quiet when batteries die, when a device is in a shielded room, or when it has left the building. Store a last_seen time and show "last seen in ICU, 2 hours ago" instead of pretending the location is current. Alert when a high-value device goes silent near an exit.

Lessons from the field

  • Map every receiver to a room in a config table, not in code. Rooms get renumbered.
  • Log raw sightings for a week before tuning MARGIN and CONFIRM.
  • Room-level accuracy needs enough receivers; software cannot fix a receiver that hears three rooms equally.

For the business side (which equipment to tag first, maintenance and audit benefits), see this guide to the hospital asset tracking system.

Top comments (0)