Insolitum Developers
Examples

Example: IoT Monitoring

A real-time IoT monitoring module that subscribes to NATS telemetry events and displays live sensor data.

Example: IoT Monitoring Module

A real-time monitoring dashboard that subscribes to NATS telemetry events and displays live sensor data.

Live Telemetry Page

src/app/page.tsx
'use client';
 
import { useEffect, useState, useCallback } from 'react';
import { useShellAuth } from '@/lib/shell-auth';
import { useNats } from '@/hooks/useNats';
import { Thermometer, Droplets, Battery, Wifi, WifiOff } from 'lucide-react';
 
interface SensorReading {
  device_id: string;
  sensor_id: string;
  temperature?: number;
  humidity?: number;
  battery?: number;
  rssi?: number;
  timestamp: string;
}
 
interface DeviceState {
  [deviceId: string]: SensorReading;
}
 
export default function MonitoringPage() {
  const { isAuthenticated } = useShellAuth();
  const { connected, subscribe } = useNats();
  const [devices, setDevices] = useState<DeviceState>({});
  const [eventCount, setEventCount] = useState(0);
 
  const handleTelemetry = useCallback((event: { data: unknown }) => {
    const reading = event.data as SensorReading;
    setDevices((prev) => ({
      ...prev,
      [reading.device_id]: reading,
    }));
    setEventCount((prev) => prev + 1);
  }, []);
 
  useEffect(() => {
    if (!connected) return;
    const unsub = subscribe('telemetry', handleTelemetry);
    return unsub;
  }, [connected, subscribe, handleTelemetry]);
 
  if (!isAuthenticated) {
    return <p className="p-6 text-gray-400">Loading...</p>;
  }
 
  const deviceList = Object.values(devices);
 
  return (
    <div className="p-6 space-y-6">
      {/* Header */}
      <div className="flex items-center justify-between">
        <div>
          <h1 className="text-2xl font-bold text-white">IoT Monitoring</h1>
          <p className="text-gray-400 mt-1">
            Real-time sensor data via NATS
          </p>
        </div>
        <div className="flex items-center gap-4">
          <div className="flex items-center gap-2">
            {connected ? (
              <Wifi className="h-4 w-4 text-green-400" />
            ) : (
              <WifiOff className="h-4 w-4 text-red-400" />
            )}
            <span className="text-sm text-gray-400">
              {connected ? 'Connected' : 'Disconnected'}
            </span>
          </div>
          <span className="text-sm text-gray-500">
            {eventCount} events received
          </span>
        </div>
      </div>
 
      {/* Device Grid */}
      {deviceList.length > 0 ? (
        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
          {deviceList.map((device) => (
            <div
              key={device.device_id}
              className="rounded-xl border border-gray-700 bg-gray-800/50 p-6"
            >
              <div className="flex items-center justify-between mb-4">
                <h3 className="text-sm font-medium text-white">
                  {device.device_id}
                </h3>
                <span className="text-xs text-gray-500">
                  {new Date(device.timestamp).toLocaleTimeString()}
                </span>
              </div>
 
              <div className="grid grid-cols-2 gap-4">
                {device.temperature !== undefined && (
                  <div className="flex items-center gap-2">
                    <Thermometer className="h-4 w-4 text-red-400" />
                    <div>
                      <p className="text-lg font-bold text-white">
                        {device.temperature.toFixed(1)}°C
                      </p>
                      <p className="text-xs text-gray-500">Temperature</p>
                    </div>
                  </div>
                )}
                {device.humidity !== undefined && (
                  <div className="flex items-center gap-2">
                    <Droplets className="h-4 w-4 text-blue-400" />
                    <div>
                      <p className="text-lg font-bold text-white">
                        {device.humidity.toFixed(1)}%
                      </p>
                      <p className="text-xs text-gray-500">Humidity</p>
                    </div>
                  </div>
                )}
                {device.battery !== undefined && (
                  <div className="flex items-center gap-2">
                    <Battery className="h-4 w-4 text-green-400" />
                    <div>
                      <p className="text-lg font-bold text-white">
                        {device.battery}%
                      </p>
                      <p className="text-xs text-gray-500">Battery</p>
                    </div>
                  </div>
                )}
              </div>
            </div>
          ))}
        </div>
      ) : (
        <div className="rounded-xl border border-gray-700 bg-gray-800/50 p-12 text-center">
          <Wifi className="h-12 w-12 text-gray-600 mx-auto mb-4" />
          <h3 className="text-lg font-medium text-white mb-2">
            Waiting for data...
          </h3>
          <p className="text-gray-400">
            {connected
              ? 'Connected to NATS. Sensor data will appear here when devices send telemetry.'
              : 'Connecting to WebSocket gateway...'}
          </p>
        </div>
      )}
    </div>
  );
}

This example demonstrates:

  • Real-time NATS event subscription via useNats()
  • Live device state management
  • Connection status indicator
  • Responsive card grid for device data
  • Graceful empty state

On this page