Skip to content

Latest commit

Β 

History

119 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🌑️ SafeSpot Toronto

Seneca Polytechnic Hackathon 2026 Theme 3 β€” Community Energy, Equity and Sustainability | Problem Statement 2

A real-time web app that helps Toronto communities stay safe during extreme heat events β€” combining live Raspberry Pi sensor data, urban heat island mapping, GPS-based routing, and cross-checked risk alerts.

Live Demo: https://safe-spot-seneca-hackathon.vercel.app

ScreenRecording2026-05-26at10 54 55PM-ezgif com-video-to-gif-converter

🧩 The Problem

In June 2021, a heat dome killed 570 people in British Columbia. Many victims lived near cooling centres β€” but had no way of knowing. Climate impacts like heatwaves disproportionately affect vulnerable populations, and there's no simple way to see where climate risk and limited shelter access overlap.


πŸ’‘ Our Solution

SafeSpot Toronto deploys a Raspberry Pi temperature sensor in a high-risk heat island zone, cross-checks live sensor readings against urban heat island data, and guides users to the nearest safe space when conditions become dangerous.

Unlike weather apps that report a city-wide average, SafeSpot measures the actual temperature where you are.


πŸ‘₯ Team codeXperts

Name Role
Gary Hardware β€” Raspberry Pi & Temperature Sensor
Marcos Backend β€” Node.js (Hono + Drizzle + PostgreSQL)
Paul Frontend β€” Next.js, Leaflet.js Map Integration
Seulgi Frontend β€” UI/UX Design, Alert System
Arun Frontend β€” GPS Location, Nearest Shelter Routing

βš™οΈ Tech Stack

Layer Technology
Frontend Next.js 16, React 19, Tailwind CSS v4, Leaflet.js
Backend Hono.js (Node.js) + Drizzle ORM + PostgreSQL
Deployment Vercel (frontend) Β· Render (backend)
Hardware Raspberry Pi + Temperature/Humidity Sensor
Map Library Leaflet.js with CartoDB Dark Matter tiles
Data Sources ArcGIS REST API, City of Toronto Open Data

✨ Core Features

πŸ“ 1. Real-Time Hardware Temperature

  • Raspberry Pi sensor physically deployed in a heat island zone
  • Captures actual ground-level temperature β€” not a city-wide average
  • Sensor readings POSTed to Hono backend at regular intervals
  • Frontend polls GET /api/sensors every 5 seconds (near real-time)
  • Source badge: distinguishes live sensor data (sensor) from test overrides (test)
  • Smart storage: danger/extreme readings stored immediately; caution throttled to 1 min; safe throttled to 5 min

πŸ—ΊοΈ 2. Urban Heat Island Map

  • Interactive Leaflet map with Toronto's urban heat island layer
  • Colour-coded risk areas: πŸ”΄ High (β‰₯30Β°C surface) / 🟠 Medium (β‰₯25Β°C) / 🟑 Low
  • Data from ArcGIS: Impervious Surface and Urban Heat Island Effect in Toronto
  • Historical surface temperature averages (not real-time β€” this is where the Pi matters)

πŸ”¬ 3. Heat Island Cross-Check

  • User's GPS location is checked against heat island GeoJSON polygons using ray-casting point-in-polygon (no external dependencies)

  • Combined risk from zone + sensor temperature:

    Sensor Temp Risk Level
    < 30Β°C Safe (no alert)
    30–35Β°C ⚠️ Caution
    35–40Β°C 🚨 Danger
    β‰₯ 40Β°C πŸ”΄ Extreme
  • Alert fires only at caution or above β€” no false warnings on safe-temperature days

🌀️ 4. City Weather Card

  • Displays Toronto's current temperature from OpenWeather API (data.main.temp)
  • Refreshes every 60 minutes
  • Shows city name and weather description alongside actual temperature

🚨 5. Danger Threshold Alerts

  • Full-screen alert banner when sensor reads 35Β°C or above
  • Web Audio API siren sound:
    • Extreme (β‰₯40Β°C): fast wailing siren (600β†’1400 Hz, 2s)
    • Danger (35–40Β°C): slow wailing siren (500β†’1100 Hz, 1.6s)
    • Caution (30–35Β°C): morse-style beep pattern (880 Hz sine)
  • Browser push notifications on alert level change

πŸ“ 6. Nearest Safe Space Routing

  • Browser GPS detects the user's current location (cached to localStorage)
  • Haversine formula calculates distance to all cooling centres and libraries
  • Shows nearest cooling centre + nearest library with compass direction (N, NE, E…)
  • Google Maps directions link with one tap

πŸ”Œ API Endpoints

Method Endpoint Description
GET /health Health check β€” returns { "status": "ok" }
POST /api/sensors Receive temperature reading from Raspberry Pi
GET /api/sensors Return latest sensor reading with alert level
GET /api/alerts List alert logs (filterable by level, zone, date)
GET /api/logs/alerts Alias for /api/alerts
GET /docs Swagger UI (OpenAPI 3.1)
GET /openapi.json OpenAPI spec

POST /api/sensors β€” Request Body

{
  "temperature": 36.2,
  "humidity": 65,
  "source": "sensor",
  "lat": 43.7,
  "lng": -79.42,
  "zone": "high"
}

GET /api/sensors β€” Response

{
  "temperature": 36.2,
  "humidity": 65,
  "humidex": 38.5,
  "timestamp": "2026-05-30T15:23:42.123Z",
  "alert": {
    "level": "danger",
    "message": "Extreme Heat Warning - Find a Cool Space Now"
  }
}

πŸ—οΈ System Architecture

Raspberry Pi (Temperature/Humidity Sensor β€” deployed in heat island zone)
        β”‚
        β–Ό  POST /api/sensors  {"temperature": 36.2, "humidity": 65}
Hono Backend (Node.js + Drizzle + PostgreSQL) β€” deployed on Render
        β”‚  stores reading Β· calculates humidex Β· logs alert events
        β–Ό  GET /api/sensors (every 5s)
Next.js Frontend β€” deployed on Vercel
        β”‚
        β”œβ”€ Sensor Card      β€” live Pi humidex + alert level
        β”œβ”€ City Weather     β€” Toronto actual temp (OpenWeather API)
        β”œβ”€ Leaflet Map      β€” heat island polygons + shelter markers
        └─ Nearest Shelter  β€” GPS cross-check + Haversine routing
                β”‚
                β–Ό
        User Browser (GPS + push notifications + audio alerts)

πŸ“‘ Data Sources

Dataset Source Format
Urban Heat Island Effect ArcGIS REST API GeoJSON
Air Conditioned & Cool Spaces City of Toronto Open Data GeoJSON
Library Branch Locations City of Toronto Open Data GeoJSON
Live Temperature + Humidity Raspberry Pi Sensor POST via Hono
City Weather OpenWeather API JSON
Reverse Geocoding OpenStreetMap Nominatim JSON

πŸ“ Project Structure

SafeSpot/
β”œβ”€β”€ frontend/                   # Next.js 16 app
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ page.js             # Main page (Story Β· How It Works Β· Dashboard)
β”‚   β”‚   └── layout.js           # Root layout + metadata
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”œβ”€β”€ AlertBanner.js      # Full-screen heat warning banner
β”‚   β”‚   β”œβ”€β”€ SensorCard.js       # Live Pi humidex + alert indicator
β”‚   β”‚   β”œβ”€β”€ WeatherCard.js      # OpenWeather city temperature
β”‚   β”‚   β”œβ”€β”€ NearestShelter.js   # GPS + heat zone cross-check + routing
β”‚   β”‚   β”œβ”€β”€ ShelterMarkers.js   # Leaflet map + heat island + shelter pins
β”‚   β”‚   β”œβ”€β”€ UserLocation.js     # GPS marker on map
β”‚   β”‚   β”œβ”€β”€ LogViewer.js        # Sensor & alert log viewer
β”‚   β”‚   β”œβ”€β”€ SmoothScroll.js     # Lenis smooth scroll wrapper
β”‚   β”‚   β”œβ”€β”€ Navbar.js
β”‚   β”‚   └── Footer.js
β”‚   └── .env.local              # API keys (see Setup)
└── backend/                    # Hono.js API server
    β”œβ”€β”€ src/
    β”‚   β”œβ”€β”€ index.js            # Server entry point (port from env)
    β”‚   β”œβ”€β”€ app.js              # Hono app + CORS + Swagger UI
    β”‚   β”œβ”€β”€ db.js               # PostgreSQL pool + table init
    β”‚   β”œβ”€β”€ schema.js           # Drizzle ORM schema
    β”‚   β”œβ”€β”€ humidex.js          # Canadian humidex formula
    β”‚   β”œβ”€β”€ alerts.js           # getAlertLevel() thresholds
    β”‚   β”œβ”€β”€ sensor-store.js     # sensor_readings DB read/write
    β”‚   β”œβ”€β”€ alerts-store.js     # alert_logs DB read/write
    β”‚   └── routes/
    β”‚       └── sensor.js       # All API route definitions
    └── tests/                  # Vitest test suite

πŸš€ Setup

Backend (Local)

cd backend
npm install
# Create .env with your PostgreSQL connection string:
# PG_URL=postgresql://user:password@host:port/dbname
npm run dev
# β†’ http://localhost:8000
# β†’ Swagger docs: http://localhost:8000/docs

Backend (Deployed)

The backend is live on Render:

https://safespot-backend-bbn6.onrender.com

Note: Render's free tier spins down after 15 minutes of inactivity. The first request after idle may take 30–60 seconds to respond.

Frontend

cd frontend
npm install
npm run dev
# β†’ http://localhost:3000

.env.local (frontend)

NEXT_PUBLIC_BACKEND_URL=https://safespot-backend-bbn6.onrender.com
NEXT_PUBLIC_OPENWEATHER_KEY=your_openweathermap_api_key

Raspberry Pi Script

import requests
import time

BACKEND_URL = "https://safespot-backend-bbn6.onrender.com"

while True:
    temp, humidity = read_sensor()  # DHT22 / DS18B20
    requests.post(f"{BACKEND_URL}/api/sensors", json={
        "temperature": temp,
        "humidity": humidity,
        "source": "sensor"
    })
    time.sleep(5)

🎬 Demo Scenario

  1. Web app opens β€” Toronto map loads with heat island risk areas
  2. Browser GPS detects user location β€” marked on map with pulsing green dot
  3. App checks if user is inside a heat island polygon (point-in-polygon)
  4. Raspberry Pi sensor reading arrives above 35Β°C
  5. App cross-checks: dangerous temperature β†’ 🚨 Danger alert fires
  6. Full-screen banner + siren sound + push notification
  7. App displays: "Nearest Cooling Centre: [Name], 0.3 km NE β†’ Get Directions"

βœ… How We Address Problem Statement 2

PS2 Requirement Our Solution
Visualize climate risk areas Urban heat island layer (High / Medium / Low heat areas on map)
Identify vulnerable communities Heat zone colour coding by risk level
Show proximity to safe shelter Cooling centres & libraries with GPS routing + Google Maps directions
Help communities prepare Real-time alerts + nearest safe space guidance
Innovative data approach Raspberry Pi sensor cross-checked with heat island map for actual risk

πŸ”‘ Why Raspberry Pi?

Weather APIs report a city-wide average. Urban heat islands mean a specific block can be 5–10Β°C hotter than the official city temperature. SafeSpot deploys the Pi inside a heat island zone to measure the actual ground-level temperature β€” then cross-checks that reading against the historical heat map to calculate your real exposure risk.

"Official forecast: 28Β°C. Your heat island zone: 36Β°C. That difference can be life or death."


Built with ❀️ by Team codeXperts · Seneca Polytechnic Hackathon 2026

Releases

Packages

Contributors

Languages