Files
sensgw/schema2.sql
2025-12-16 12:50:46 +06:00

164 lines
5.3 KiB
PL/PgSQL

begin;
-- roles
alter schema public owner to sensor_admin;
grant usage on schema public to sensor_writer;
grant all on all tables in schema public to sensor_admin;
grant all on all sequences in schema public to sensor_admin;
grant insert, update, select on all tables in schema public to sensor_writer;
grant usage, select on all sequences in schema public to sensor_writer;
alter default privileges for role sensor_admin in schema public
grant insert, update, select on tables to sensor_writer;
alter default privileges for role sensor_admin in schema public
grant usage, select on sequences to sensor_writer;
-- pg_partman
create schema if not exists partman;
create extension if not exists pg_partman schema partman;
do $$
begin
if not exists (select 1 from pg_roles where rolname = 'partman_user') then
create role partman_user with login;
end if;
end$$;
grant all on schema partman to partman_user;
grant all on all tables in schema partman to partman_user;
grant execute on all functions in schema partman to partman_user;
grant execute on all procedures in schema partman to partman_user;
grant all on schema public to partman_user;
grant all on all tables in schema public to partman_user;
grant temporary on database sensor_db to partman_user;
grant create on database sensor_db to partman_user;
grant usage, create on schema partman to sensor_admin;
grant execute on all functions in schema partman to sensor_admin;
grant all on all tables in schema partman to sensor_admin;
grant all on all sequences in schema partman to sensor_admin;
set role sensor_admin;
-- physical/transport endpoints
create table if not exists endpoints (
endpoint_id int primary key generated by default as identity,
endpoint_key text not null unique,
-- 'snmp' | 'mqtt' | 'visa'
protocol text not null,
conn jsonb not null default '{}'::jsonb,
is_enabled boolean not null default true,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index if not exists idx_endpoints_enabled_protocol
on endpoints (is_enabled, protocol);
create table if not exists locations (
location_id int primary key generated by default as identity,
name text not null,
is_active bool not null default true,
constraint locations_name_unique unique (name)
);
create table if not exists devices (
device_id int primary key generated by default as identity,
-- "snmp:10.0.0.12:probe1"
-- "mqtt:esp32-1"
-- "visa:prologix:gpib5"
device_key text not null unique,
endpoint_id int references endpoints(endpoint_id),
location_id int references locations(location_id),
is_enabled boolean not null default true,
metadata jsonb not null default '{}'::jsonb,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index if not exists idx_devices_endpoint on devices (endpoint_id);
create index if not exists idx_devices_location on devices (location_id);
create index if not exists idx_devices_enabled on devices (is_enabled);
-- per-device measurement defs
create table if not exists device_channels (
channel_id int primary key generated by default as identity,
device_id int not null references devices(device_id) on delete cascade,
-- corresponds to a column name in sensor_data (wide mapping)
metric text not null,
-- SNMP: {"type":"snmp_oid","oid":".1.3.6...","datatype":"float"}
-- MQTT: {"type":"mqtt_topic","topic":"sensors/x/telemetry","payload":"json","field":"temperature_c"}
-- VISA: {"type":"scpi","query":"MEAS:VOLT:DC?","read_termination":"\n"}
source jsonb not null,
scale_value double precision not null default 1.0,
offset_value double precision not null default 0.0,
poll_interval_s int,
is_enabled boolean not null default true,
created_at timestamptz not null default now(),
constraint device_channels_unique_metric unique (device_id, metric)
);
create index if not exists idx_device_channels_device on device_channels (device_id);
-- device health/status
create table if not exists device_status (
device_id int primary key references devices(device_id) on delete cascade,
last_seen timestamptz,
last_ok timestamptz,
last_error_at timestamptz,
last_error text,
updated_at timestamptz not null default now()
);
create table if not exists sensor_data (
ts timestamptz not null,
device_id int not null references devices(device_id),
location_id int references locations(location_id),
temp_c real,
humidity_rh real,
pressure_pa real,
light_lux real,
soil_moist real,
co2_ppm real,
voltage_v real,
current_a real,
resistance_ohm real,
freq_hz real,
power_w real,
constraint sensor_data_pk primary key (device_id, ts)
) partition by range (ts);
create index if not exists idx_sensor_data_device_ts on sensor_data (device_id, ts desc);
create index if not exists idx_sensor_data_location_ts on sensor_data (location_id, ts desc);
create index if not exists idx_sensor_data_ts_brin on sensor_data using brin(ts);
-- partition
select partman.create_parent(
p_parent_table => 'public.sensor_data',
p_control => 'ts',
p_interval => '1 year',
p_premake => 2
);
commit;