package hamview const ( sqlCreateRadio = ` CREATE TABLE IF NOT EXISTS radio ( id BIGSERIAL PRIMARY KEY, name VARCHAR(64) NOT NULL UNIQUE, is_online BOOLEAN NOT NULL DEFAULT false, device VARCHAR(100), manufacturer VARCHAR(100), firmware_date TIMESTAMPTZ, firmware_version VARCHAR(32), antenna VARCHAR(100), modulation VARCHAR(16) NOT NULL, protocol VARCHAR(16) NOT NULL, latitude NUMERIC(10, 8), -- GPS latitude in decimal degrees longitude NUMERIC(11, 8), -- GPS longitude in decimal degrees altitude REAL, -- Altitude in meters frequency DOUBLE PRECISION, bandwidth DOUBLE PRECISION, rx_frequency DOUBLE PRECISION, tx_frequency DOUBLE PRECISION, power REAL, gain REAL, lora_sf SMALLINT, lora_cr SMALLINT, extra JSONB ); ` sqlIndexRadioName = `CREATE INDEX IF NOT EXISTS idx_radio_name ON radio(name);` sqlIndexRadioProtocol = `CREATE INDEX IF NOT EXISTS idx_radio_protocol ON radio(protocol);` sqlGeometryRadioPosition = `SELECT AddGeometryColumn('public', 'radio', 'position', 4326, 'POINT', 2);` ) const ( sqlCreateAPRSStation = ` CREATE TABLE IF NOT EXISTS aprs_station ( id BIGSERIAL PRIMARY KEY, address VARCHAR(10) NOT NULL UNIQUE, last_heard TIMESTAMPTZ NOT NULL, last_path TEXT[], last_comment TEXT ); ` sqlCreateAPRSPacket = ` CREATE TABLE IF NOT EXISTS aprs_packet ( id BIGSERIAL PRIMARY KEY, src_address VARCHAR(10) NOT NULL, dst_address VARCHAR(10) NOT NULL, comment TEXT, payload BYTEA, raw BYTEA, received_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); ` ) const ( sqlCreateMeshCorePacket = ` CREATE TABLE IF NOT EXISTS meshcore_packet ( id BIGSERIAL PRIMARY KEY, snr REAL NOT NULL DEFAULT 0, rssi SMALLINT NOT NULL DEFAULT 0, hash BYTEA NOT NULL, -- Used for deduplication route_type SMALLINT NOT NULL, payload_type SMALLINT NOT NULL, path BYTEA, payload BYTEA, raw BYTEA, parsed JSONB, received_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); ` sqlIndexMeshCorePacketHash = `CREATE INDEX IF NOT EXISTS idx_meshcore_packet_hash ON meshcore_packet(hash);` sqlIndexMeshCorePacketPayloadType = `CREATE INDEX IF NOT EXISTS idx_meshcore_packet_payload_type ON meshcore_packet(payload_type);` ) const ( sqlCreateMeshCoreNode = ` CREATE TABLE IF NOT EXISTS meshcore_node ( id BIGSERIAL PRIMARY KEY, last_advert_id BIGINT NOT NULL REFERENCES meshcore_packet(id) ON DELETE CASCADE, node_type SMALLINT NOT NULL DEFAULT 0, public_key BYTEA NOT NULL UNIQUE, name TEXT, local_time TIMESTAMPTZ NOT NULL, first_heard TIMESTAMPTZ NOT NULL DEFAULT NOW(), last_heard TIMESTAMPTZ NOT NULL DEFAULT NOW(), last_latitude NUMERIC(10, 8), -- GPS latitude in decimal degrees last_longitude NUMERIC(11, 8), -- GPS longitude in decimal degrees last_position GEOMETRY(POINT, 4326) ); ` sqlIndexMeshCoreNodePublicKey = `CREATE INDEX IF NOT EXISTS idx_meshcore_node_public_key ON meshcore_node(public_key);` sqlIndexMeshCoreNodeName = `CREATE INDEX IF NOT EXISTS idx_meshcore_node_name ON meshcore_node(name);` sqlAlterMeshCoreNodePrefix = `ALTER TABLE meshcore_node ADD COLUMN IF NOT EXISTS prefix BYTEA GENERATED ALWAYS AS (substring(public_key, 0, 2)) STORED;` sqlGeometryMeshCoreNodePosition = `SELECT AddGeometryColumn('public', 'meshcore_node', 'position', 4326, 'POINT', 2);` sqlAlterMeshCoreNodeLastPosition = ` ALTER TABLE meshcore_node ADD COLUMN last_position GEOMETRY(Point, 4326) GENERATED ALWAYS AS ( CASE WHEN last_latitude IS NOT NULL AND last_longitude IS NOT NULL THEN ST_SetSRID(ST_MakePoint(last_latitude, last_longitude), 4326) ELSE NULL END ) STORED;` ) const ( sqlCreateMeshCoreNodePosition = ` CREATE TABLE IF NOT EXISTS meshcore_node_position ( id BIGSERIAL PRIMARY KEY, node_id BIGINT NOT NULL REFERENCES meshcore_node(id) ON DELETE CASCADE, heard_at TIMESTAMPTZ NOT NULL, latitude NUMERIC(10, 8), -- GPS latitude in decimal degrees longitude NUMERIC(11, 8) -- GPS longitude in decimal degrees ); ` sqlGeometryMeshCoreNodePositionPosition = `SELECT AddGeometryColumn('public', 'meshcore_node_position', 'position', 4326, 'POINT', 2);` sqlIndexMeshCoreNodePositionPosition = `CREATE INDEX IF NOT EXISTS idx_meshcore_node_position_position ON meshcore_node_position USING GIST (position);` ) const ( sqlSelectMeshCoreNodesLastPosition = ` WITH ranked_positions AS ( SELECT node_id, latitude, longitude, position, ROW_NUMBER() OVER (PARTITION BY node_id ORDER BY heard_at DESC) as rn FROM meshcore_node_position ) SELECT r.snr, r.rssi, n.name, n.public_key, n.prefix, n.node_type, n.first_heard, n.last_heard, p.latitude, p.longitude FROM meshcore_node n LEFT JOIN ranked_positions p ON n.id = p.node_id AND p.rn = 1 LEFT JOIN meshcore_packet r ON r.id = n.last_advert_id WHERE n.node_type = $1 ORDER BY last_heard DESC LIMIT $2; ` sqlSelectMeshCorePackets = ` SELECT snr, rssi, hash, route_type, payload_type, path, received_at, raw, parsed FROM meshcore_packet ORDER BY received_at DESC LIMIT $1; ` sqlSelectMeshCorePacketsByHash = ` SELECT snr, rssi, hash, route_type, payload_type, path, received_at, raw, parsed FROM meshcore_packet WHERE hash = $1 ORDER BY received_at DESC; ` sqlSelectMeshCorePacketsByRepeaterWindowed = ` SELECT to_timestamp(round(EXTRACT(EPOCH FROM received_at) / $1) * $1) as window, cast(to_hex(get_byte(path, length(path)-2)) as text) AS repeater, count(id) AS packets FROM meshcore_packet WHERE length(path) >= 2 AND received_at >= $2 GROUP BY round(EXTRACT(EPOCH FROM received_at) / $1), cast(to_hex(get_byte(path, length(path)-2)) as text); ` sqlSelectMeshCorePacketPathNodes = ` WITH RECURSIVE params AS ( $1::BYTEA as path, $2::NUMERIC(10, 8) as start_latitude, $3::NUMERIC(11, 8) as start_longitude, $4::DOUBLE PRECISION as max_range_m ), path_prefix AS ( SELECT ) ` ) const ( sqlCreateMeshCoreIdentity = ` CREATE TABLE IF NOT EXISTS meshcore_identity ( id BIGSERIAL PRIMARY KEY, name VARCHAR(32) NOT NULL UNIQUE, public_key BYTEA(32) NOT NULL UNIQUE, private_key BYTEA(64) NOT NULL ); ` ) const ( sqlCreateMeshCoreGroup = ` CREATE TABLE IF NOT EXISTS meshcore_group ( id BIGSERIAL PRIMARY KEY, name VARCHAR(32) NOT NULL UNIQUE, hash SMALLINT NOT NULL, shared_key VARCHAR(64) NOT NULL, is_public BOOLEAN NOT NULL DEFAULT FALSE ); ` )