Initial commit of akmon project
This commit is contained in:
179
locations.sql
Normal file
179
locations.sql
Normal file
@@ -0,0 +1,179 @@
|
||||
-- Location tracking schema for 2.4G gateway based wearable positioning
|
||||
-- Run this script in Supabase/PostgreSQL environment after ensuring uuid-ossp extension is available.
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||
|
||||
-- =============================================================
|
||||
-- 1. 2.4G Gateways registry
|
||||
-- =============================================================
|
||||
CREATE TABLE IF NOT EXISTS location_gateways (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
organization_id UUID, -- optional, reference to owning org / school (wire manually)
|
||||
campus_code TEXT, -- logical campus/region grouping code
|
||||
area_name TEXT, -- eg. East Campus, Zone B
|
||||
building_name TEXT,
|
||||
floor_label TEXT,
|
||||
room_label TEXT,
|
||||
name TEXT NOT NULL, -- human friendly name
|
||||
system_code TEXT NOT NULL UNIQUE, -- system/asset identifier
|
||||
serial_number TEXT,
|
||||
description TEXT,
|
||||
|
||||
latitude DECIMAL(10, 8) NOT NULL,
|
||||
longitude DECIMAL(11, 8) NOT NULL,
|
||||
altitude_m NUMERIC(8, 2),
|
||||
coordinate_system TEXT DEFAULT 'WGS84', -- WGS84 / GCJ02 / BD09 etc
|
||||
|
||||
install_height_m NUMERIC(6, 2),
|
||||
orientation_deg NUMERIC(5, 2),
|
||||
coverage_radius_m NUMERIC(6, 2),
|
||||
coverage_notes TEXT,
|
||||
|
||||
ip_address INET,
|
||||
lan_mac MACADDR,
|
||||
upstream_mac MACADDR,
|
||||
firmware_version TEXT,
|
||||
hardware_version TEXT,
|
||||
heartbeat_interval_s INTEGER,
|
||||
|
||||
status TEXT DEFAULT 'active' CHECK (status IN ('active', 'maintenance', 'inactive', 'retired')),
|
||||
last_online_at TIMESTAMPTZ,
|
||||
last_maintenance_at TIMESTAMPTZ,
|
||||
|
||||
tags TEXT[],
|
||||
extra JSONB,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
COMMENT ON TABLE location_gateways IS 'Registry of 2.4G gateways installed across campuses.';
|
||||
COMMENT ON COLUMN location_gateways.extra IS 'Extensible JSON payload for vendor-specific metadata.';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_location_gateways_org ON location_gateways(organization_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_location_gateways_geo ON location_gateways(latitude, longitude);
|
||||
CREATE INDEX IF NOT EXISTS idx_location_gateways_status ON location_gateways(status);
|
||||
|
||||
-- Auto update trigger for updated_at
|
||||
CREATE OR REPLACE FUNCTION trg_location_gateways_touch() RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at := NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_location_gateways_touch ON location_gateways;
|
||||
CREATE TRIGGER trg_location_gateways_touch
|
||||
BEFORE UPDATE ON location_gateways
|
||||
FOR EACH ROW EXECUTE FUNCTION trg_location_gateways_touch();
|
||||
|
||||
-- =============================================================
|
||||
-- 2. Wearable location snapshots (per time slice, per device)
|
||||
-- =============================================================
|
||||
CREATE TABLE IF NOT EXISTS wearable_location_snapshots (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
device_id UUID NOT NULL REFERENCES public.ak_devices(id) ON DELETE CASCADE,
|
||||
user_id UUID REFERENCES public.ak_users(id) ON DELETE SET NULL,
|
||||
|
||||
estimated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
window_started_at TIMESTAMPTZ,
|
||||
window_ended_at TIMESTAMPTZ,
|
||||
|
||||
latitude DECIMAL(10, 8),
|
||||
longitude DECIMAL(11, 8),
|
||||
altitude_m NUMERIC(8, 2),
|
||||
coordinate_system TEXT DEFAULT 'WGS84',
|
||||
|
||||
uncertainty_radius_m NUMERIC(6, 2), -- estimated accuracy / radius (meters)
|
||||
confidence NUMERIC(4, 2), -- 0.00 - 1.00
|
||||
method TEXT, -- e.g. WCL, Trilateration, Kalman
|
||||
algorithm_version TEXT,
|
||||
observation_count INTEGER DEFAULT 0,
|
||||
|
||||
campus_code TEXT,
|
||||
area_name TEXT,
|
||||
building_name TEXT,
|
||||
floor_label TEXT,
|
||||
room_label TEXT,
|
||||
|
||||
observations JSONB, -- optional denormalized structure of gateway RSSI readings
|
||||
diagnostics JSONB, -- troubleshooting info (residuals, covariance etc)
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE wearable_location_snapshots IS 'Estimated wearable locations derived from multi-gateway RSSI aggregation.';
|
||||
COMMENT ON COLUMN wearable_location_snapshots.observations IS 'Optional JSON containing gateway RSSI array for quick lookup.';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_wearable_snapshots_device_time ON wearable_location_snapshots(device_id, estimated_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_wearable_snapshots_user_time ON wearable_location_snapshots(user_id, estimated_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_wearable_snapshots_geo ON wearable_location_snapshots(latitude, longitude);
|
||||
|
||||
CREATE OR REPLACE FUNCTION trg_wearable_snapshots_touch() RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at := NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_wearable_snapshots_touch ON wearable_location_snapshots;
|
||||
CREATE TRIGGER trg_wearable_snapshots_touch
|
||||
BEFORE UPDATE ON wearable_location_snapshots
|
||||
FOR EACH ROW EXECUTE FUNCTION trg_wearable_snapshots_touch();
|
||||
|
||||
-- =============================================================
|
||||
-- 3. Raw gateway RSSI observations per snapshot
|
||||
-- =============================================================
|
||||
CREATE TABLE IF NOT EXISTS wearable_location_observations (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
snapshot_id UUID NOT NULL REFERENCES wearable_location_snapshots(id) ON DELETE CASCADE,
|
||||
gateway_id UUID NOT NULL REFERENCES location_gateways(id) ON DELETE CASCADE,
|
||||
|
||||
received_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
gateway_time TIMESTAMPTZ,
|
||||
|
||||
rssi_dbm NUMERIC(5, 2) NOT NULL,
|
||||
snr_db NUMERIC(5, 2),
|
||||
distance_m NUMERIC(7, 2), -- computed from RSSI if available
|
||||
channel INTEGER,
|
||||
frequency_mhz NUMERIC(6, 2),
|
||||
packet_sequence INTEGER,
|
||||
latency_ms INTEGER,
|
||||
|
||||
firmware_version TEXT,
|
||||
payload JSONB,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE wearable_location_observations IS 'Raw 2.4G gateway readings contributing to a wearable location snapshot.';
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_observations_unique_sample
|
||||
ON wearable_location_observations(snapshot_id, gateway_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_observations_gateway_time
|
||||
ON wearable_location_observations(gateway_id, received_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_observations_snapshot ON wearable_location_observations(snapshot_id);
|
||||
|
||||
-- Optional view for latest snapshot per device
|
||||
CREATE OR REPLACE VIEW wearable_latest_location AS
|
||||
SELECT DISTINCT ON (device_id)
|
||||
device_id,
|
||||
id AS snapshot_id,
|
||||
estimated_at,
|
||||
latitude,
|
||||
longitude,
|
||||
altitude_m,
|
||||
uncertainty_radius_m,
|
||||
confidence,
|
||||
method,
|
||||
algorithm_version,
|
||||
created_at
|
||||
FROM wearable_location_snapshots
|
||||
ORDER BY device_id, estimated_at DESC;
|
||||
|
||||
COMMENT ON VIEW wearable_latest_location IS 'Convenience view returning the latest computed position per wearable device.';
|
||||
Reference in New Issue
Block a user