weather-portal/PLAN.md

3.1 KiB

Plan: Balcony Weather Station Dashboard

1. Project Overview

A real-time, neighborhood-facing weather dashboard that streams sensory data from an MQTT broker (Home Assistant) to a web interface.

Tech Stack

  • Backend: Gleam (Target: Erlang/OTP)
  • Web Server: Mist (HTTP & WebSockets)
  • Database: SQLite (via sqlight) for persistent uptime tracking
  • Frontend: SolidJS (Signals-based reactivity) + Tailwind CSS
  • Infrastructure: Nomad (Docker-based deployment)

2. Core Architecture & Actors

  • MQTT Actor: Subscribes to weather topics (e.g., tele/sensor/SENSOR), parses JSON, and broadcasts updates.
  • Monitor Actor: Tracks sensor "heartbeats." Maintains a state of "Last Seen."
  • WebSocket Manager: Handles browser connections; pushes HTML-ready JSON to SolidJS.
  • Storage: Single weather.db file using "Schema-on-Boot" (no manual migrations).

3. Implementation Phases

Phase 1: Backend Infrastructure (Gleam)

  • Initialize Gleam project with gleam_otp, mist, wisp, and sqlight.
  • Implement database.gleam:
    • Function init_db to run CREATE TABLE IF NOT EXISTS sensor_stats.
    • Schema: sensor_id (PK), last_seen (DATETIME), uptime_start (DATETIME).
  • Implement mqtt_handler.gleam:
    • Use gemqtt (wrapper for emqtt) to connect to the broker.
    • Map incoming payloads to a WeatherUpdate custom type.

Phase 2: Uptime Logic

  • Implement the Monitor Actor logic:
    • On MQTT message: Update last_seen in SQLite.
    • If (CurrentTime - last_seen) > 10 minutes, consider the sensor "disrupted."
    • On recovery: Reset uptime_start to now.
  • Calculate "Days since disruption" using: (CurrentTime - UptimeStart) / 86400

Phase 3: Real-time Streaming

  • Set up a Mist WebSocket handler.
  • Use a simple process registry (or gleam_otp subject) to broadcast JSON to all connected clients.
  • Ensure the JSON payload includes: temp, humidity, wind, and uptime_days.

Phase 4: Frontend (SolidJS)

  • Scaffold SolidJS via Vite.
  • Create a WeatherCard component.
  • Implement createEffect for WebSocket management:
    • On ws.onmessage: Update Solid signals.
    • On ws.onclose: Implement simple exponential backoff for reconnection.
  • Style with Tailwind CSS (Card-based layout, dark mode).

Phase 5: Deployment (Nomad)

  • Create a multi-stage Dockerfile:
    • Build SolidJS assets.
    • Compile Gleam to a production Erlang release.
  • Create weather.nomad job file:
    • Mount host_volume for the .db file.
    • Configure networking for the WebSocket port (default 8080).

4. Claude Code Implementation Instructions

  1. Start with the Backend: Focus on the WeatherUpdate type and the MQTT subscriber first.
  2. Database: Use sqlight.exec to ensure the table exists on every app start.
  3. Frontend: Keep the SolidJS app in a ./frontend subdirectory.
  4. Mocking: If the MQTT broker isn't reachable during coding, create a "Simulator" actor that sends random weather data every 5 seconds.