Meters columns
This commit is contained in:
124
water-api/sql/add_meter_extended_fields.sql
Normal file
124
water-api/sql/add_meter_extended_fields.sql
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- Add extended fields to meters table
|
||||||
|
-- These fields store additional technical and operational data for meters
|
||||||
|
-- All fields are nullable (not required)
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- Communication & Network Fields
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS protocol VARCHAR(50);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS mac VARCHAR(50);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS gateway VARCHAR(100);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS network_mode VARCHAR(50);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS phone_id VARCHAR(50);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS phone_model VARCHAR(100);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS phone_name VARCHAR(100);
|
||||||
|
|
||||||
|
-- Voltage & Power Fields
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS voltage DECIMAL(10, 2);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS voltage_rtu DECIMAL(10, 2);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS voltage_status VARCHAR(50);
|
||||||
|
|
||||||
|
-- Signal & Communication Quality
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS signal INTEGER;
|
||||||
|
|
||||||
|
-- Status Fields
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS storage_status VARCHAR(50);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS flow_status VARCHAR(50);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS open_status VARCHAR(50);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS actuator_status VARCHAR(50);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS counter_status VARCHAR(50);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS leakage_status VARCHAR(50);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS burst_status VARCHAR(50);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS valid_status VARCHAR(50);
|
||||||
|
|
||||||
|
-- Security & Alerts
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS magnetic_attack BOOLEAN;
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS realtime_information_flag BOOLEAN;
|
||||||
|
|
||||||
|
-- Flow Measurements
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS current_flow DECIMAL(15, 4);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS total_flow_reverse DECIMAL(15, 4);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS current_flow_reverse DECIMAL(15, 4);
|
||||||
|
|
||||||
|
-- Protocol Fields (M-Bus/LoRaWAN specific)
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS l_field VARCHAR(10);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS c_field VARCHAR(10);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS ver VARCHAR(10);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS dev VARCHAR(20);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS ci_field VARCHAR(10);
|
||||||
|
|
||||||
|
-- Company & Manufacturer Info
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS company_abbreviation VARCHAR(50);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS manufacturer VARCHAR(100);
|
||||||
|
|
||||||
|
-- Geolocation
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS latitude DECIMAL(10, 8);
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS longitude DECIMAL(11, 8);
|
||||||
|
|
||||||
|
-- Additional Data (JSON for flexible data storage)
|
||||||
|
ALTER TABLE meters ADD COLUMN IF NOT EXISTS data JSONB;
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- Add indexes for commonly queried fields
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_meters_protocol ON meters(protocol);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_meters_mac ON meters(mac);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_meters_gateway ON meters(gateway);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_meters_manufacturer ON meters(manufacturer);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_meters_flow_status ON meters(flow_status);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_meters_leakage_status ON meters(leakage_status);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_meters_geolocation ON meters(latitude, longitude) WHERE latitude IS NOT NULL AND longitude IS NOT NULL;
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- Add comments for documentation
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
COMMENT ON COLUMN meters.protocol IS 'Communication protocol (LoRa, LoRaWAN, NB-IoT, etc.)';
|
||||||
|
COMMENT ON COLUMN meters.mac IS 'MAC address of the device';
|
||||||
|
COMMENT ON COLUMN meters.gateway IS 'Gateway identifier or name';
|
||||||
|
COMMENT ON COLUMN meters.network_mode IS 'Network operation mode';
|
||||||
|
COMMENT ON COLUMN meters.voltage IS 'Battery voltage (V)';
|
||||||
|
COMMENT ON COLUMN meters.voltage_rtu IS 'RTU voltage (V)';
|
||||||
|
COMMENT ON COLUMN meters.voltage_status IS 'Battery status (OK, LOW, CRITICAL)';
|
||||||
|
COMMENT ON COLUMN meters.signal IS 'Signal strength (RSSI or similar)';
|
||||||
|
COMMENT ON COLUMN meters.storage_status IS 'Internal storage status';
|
||||||
|
COMMENT ON COLUMN meters.flow_status IS 'Flow measurement status';
|
||||||
|
COMMENT ON COLUMN meters.leakage_status IS 'Leak detection status';
|
||||||
|
COMMENT ON COLUMN meters.burst_status IS 'Burst pipe detection status';
|
||||||
|
COMMENT ON COLUMN meters.magnetic_attack IS 'Magnetic tampering detected';
|
||||||
|
COMMENT ON COLUMN meters.realtime_information_flag IS 'Real-time data available';
|
||||||
|
COMMENT ON COLUMN meters.current_flow IS 'Current flow rate (m³/h or L/h)';
|
||||||
|
COMMENT ON COLUMN meters.total_flow_reverse IS 'Total reverse flow accumulated';
|
||||||
|
COMMENT ON COLUMN meters.current_flow_reverse IS 'Current reverse flow rate';
|
||||||
|
COMMENT ON COLUMN meters.l_field IS 'M-Bus L-Field (length)';
|
||||||
|
COMMENT ON COLUMN meters.c_field IS 'M-Bus C-Field (control)';
|
||||||
|
COMMENT ON COLUMN meters.ver IS 'Protocol version';
|
||||||
|
COMMENT ON COLUMN meters.dev IS 'Device type identifier';
|
||||||
|
COMMENT ON COLUMN meters.ci_field IS 'M-Bus CI-Field (control information)';
|
||||||
|
COMMENT ON COLUMN meters.latitude IS 'Latitude coordinate (WGS84)';
|
||||||
|
COMMENT ON COLUMN meters.longitude IS 'Longitude coordinate (WGS84)';
|
||||||
|
COMMENT ON COLUMN meters.data IS 'Additional flexible data storage (JSON)';
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- Verify the changes
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
column_name,
|
||||||
|
data_type,
|
||||||
|
is_nullable,
|
||||||
|
column_default
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'meters'
|
||||||
|
AND column_name IN (
|
||||||
|
'protocol', 'mac', 'gateway', 'network_mode', 'phone_id', 'phone_model',
|
||||||
|
'phone_name', 'voltage', 'voltage_rtu', 'voltage_status', 'signal',
|
||||||
|
'storage_status', 'flow_status', 'open_status', 'actuator_status',
|
||||||
|
'counter_status', 'leakage_status', 'burst_status', 'valid_status',
|
||||||
|
'magnetic_attack', 'realtime_information_flag', 'current_flow',
|
||||||
|
'total_flow_reverse', 'current_flow_reverse', 'l_field', 'c_field',
|
||||||
|
'ver', 'dev', 'ci_field', 'company_abbreviation', 'manufacturer',
|
||||||
|
'latitude', 'longitude', 'data'
|
||||||
|
)
|
||||||
|
ORDER BY ordinal_position;
|
||||||
@@ -18,6 +18,60 @@ export interface Meter {
|
|||||||
installation_date: Date | null;
|
installation_date: Date | null;
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
updated_at: Date;
|
updated_at: Date;
|
||||||
|
|
||||||
|
// Communication & Network Fields
|
||||||
|
protocol?: string | null;
|
||||||
|
mac?: string | null;
|
||||||
|
gateway?: string | null;
|
||||||
|
network_mode?: string | null;
|
||||||
|
phone_id?: string | null;
|
||||||
|
phone_model?: string | null;
|
||||||
|
phone_name?: string | null;
|
||||||
|
|
||||||
|
// Voltage & Power Fields
|
||||||
|
voltage?: number | null;
|
||||||
|
voltage_rtu?: number | null;
|
||||||
|
voltage_status?: string | null;
|
||||||
|
|
||||||
|
// Signal & Communication Quality
|
||||||
|
signal?: number | null;
|
||||||
|
|
||||||
|
// Status Fields
|
||||||
|
storage_status?: string | null;
|
||||||
|
flow_status?: string | null;
|
||||||
|
open_status?: string | null;
|
||||||
|
actuator_status?: string | null;
|
||||||
|
counter_status?: string | null;
|
||||||
|
leakage_status?: string | null;
|
||||||
|
burst_status?: string | null;
|
||||||
|
valid_status?: string | null;
|
||||||
|
|
||||||
|
// Security & Alerts
|
||||||
|
magnetic_attack?: boolean | null;
|
||||||
|
realtime_information_flag?: boolean | null;
|
||||||
|
|
||||||
|
// Flow Measurements
|
||||||
|
current_flow?: number | null;
|
||||||
|
total_flow_reverse?: number | null;
|
||||||
|
current_flow_reverse?: number | null;
|
||||||
|
|
||||||
|
// Protocol Fields (M-Bus/LoRaWAN specific)
|
||||||
|
l_field?: string | null;
|
||||||
|
c_field?: string | null;
|
||||||
|
ver?: string | null;
|
||||||
|
dev?: string | null;
|
||||||
|
ci_field?: string | null;
|
||||||
|
|
||||||
|
// Company & Manufacturer Info
|
||||||
|
company_abbreviation?: string | null;
|
||||||
|
manufacturer?: string | null;
|
||||||
|
|
||||||
|
// Geolocation
|
||||||
|
latitude?: number | null;
|
||||||
|
longitude?: number | null;
|
||||||
|
|
||||||
|
// Additional Data
|
||||||
|
data?: Record<string, any> | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,6 +128,42 @@ export interface CreateMeterInput {
|
|||||||
type?: string;
|
type?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
installation_date?: string;
|
installation_date?: string;
|
||||||
|
|
||||||
|
// Extended fields (all optional)
|
||||||
|
protocol?: string;
|
||||||
|
mac?: string;
|
||||||
|
gateway?: string;
|
||||||
|
network_mode?: string;
|
||||||
|
phone_id?: string;
|
||||||
|
phone_model?: string;
|
||||||
|
phone_name?: string;
|
||||||
|
voltage?: number;
|
||||||
|
voltage_rtu?: number;
|
||||||
|
voltage_status?: string;
|
||||||
|
signal?: number;
|
||||||
|
storage_status?: string;
|
||||||
|
flow_status?: string;
|
||||||
|
open_status?: string;
|
||||||
|
actuator_status?: string;
|
||||||
|
counter_status?: string;
|
||||||
|
leakage_status?: string;
|
||||||
|
burst_status?: string;
|
||||||
|
valid_status?: string;
|
||||||
|
magnetic_attack?: boolean;
|
||||||
|
realtime_information_flag?: boolean;
|
||||||
|
current_flow?: number;
|
||||||
|
total_flow_reverse?: number;
|
||||||
|
current_flow_reverse?: number;
|
||||||
|
l_field?: string;
|
||||||
|
c_field?: string;
|
||||||
|
ver?: string;
|
||||||
|
dev?: string;
|
||||||
|
ci_field?: string;
|
||||||
|
company_abbreviation?: string;
|
||||||
|
manufacturer?: string;
|
||||||
|
latitude?: number;
|
||||||
|
longitude?: number;
|
||||||
|
data?: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,6 +178,42 @@ export interface UpdateMeterInput {
|
|||||||
type?: string;
|
type?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
installation_date?: string;
|
installation_date?: string;
|
||||||
|
|
||||||
|
// Extended fields (all optional)
|
||||||
|
protocol?: string;
|
||||||
|
mac?: string;
|
||||||
|
gateway?: string;
|
||||||
|
network_mode?: string;
|
||||||
|
phone_id?: string;
|
||||||
|
phone_model?: string;
|
||||||
|
phone_name?: string;
|
||||||
|
voltage?: number;
|
||||||
|
voltage_rtu?: number;
|
||||||
|
voltage_status?: string;
|
||||||
|
signal?: number;
|
||||||
|
storage_status?: string;
|
||||||
|
flow_status?: string;
|
||||||
|
open_status?: string;
|
||||||
|
actuator_status?: string;
|
||||||
|
counter_status?: string;
|
||||||
|
leakage_status?: string;
|
||||||
|
burst_status?: string;
|
||||||
|
valid_status?: string;
|
||||||
|
magnetic_attack?: boolean;
|
||||||
|
realtime_information_flag?: boolean;
|
||||||
|
current_flow?: number;
|
||||||
|
total_flow_reverse?: number;
|
||||||
|
current_flow_reverse?: number;
|
||||||
|
l_field?: string;
|
||||||
|
c_field?: string;
|
||||||
|
ver?: string;
|
||||||
|
dev?: string;
|
||||||
|
ci_field?: string;
|
||||||
|
company_abbreviation?: string;
|
||||||
|
manufacturer?: string;
|
||||||
|
latitude?: number;
|
||||||
|
longitude?: number;
|
||||||
|
data?: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -73,6 +73,60 @@ export const createMeterSchema = z.object({
|
|||||||
.datetime({ message: 'Installation date must be a valid ISO date string' })
|
.datetime({ message: 'Installation date must be a valid ISO date string' })
|
||||||
.optional()
|
.optional()
|
||||||
.nullable(),
|
.nullable(),
|
||||||
|
|
||||||
|
// Communication & Network Fields
|
||||||
|
protocol: z.string().max(50).optional().nullable(),
|
||||||
|
mac: z.string().max(50).optional().nullable(),
|
||||||
|
gateway: z.string().max(100).optional().nullable(),
|
||||||
|
network_mode: z.string().max(50).optional().nullable(),
|
||||||
|
phone_id: z.string().max(50).optional().nullable(),
|
||||||
|
phone_model: z.string().max(100).optional().nullable(),
|
||||||
|
phone_name: z.string().max(100).optional().nullable(),
|
||||||
|
|
||||||
|
// Voltage & Power Fields
|
||||||
|
voltage: z.number().optional().nullable(),
|
||||||
|
voltage_rtu: z.number().optional().nullable(),
|
||||||
|
voltage_status: z.string().max(50).optional().nullable(),
|
||||||
|
|
||||||
|
// Signal & Communication Quality
|
||||||
|
signal: z.number().int().optional().nullable(),
|
||||||
|
|
||||||
|
// Status Fields
|
||||||
|
storage_status: z.string().max(50).optional().nullable(),
|
||||||
|
flow_status: z.string().max(50).optional().nullable(),
|
||||||
|
open_status: z.string().max(50).optional().nullable(),
|
||||||
|
actuator_status: z.string().max(50).optional().nullable(),
|
||||||
|
counter_status: z.string().max(50).optional().nullable(),
|
||||||
|
leakage_status: z.string().max(50).optional().nullable(),
|
||||||
|
burst_status: z.string().max(50).optional().nullable(),
|
||||||
|
valid_status: z.string().max(50).optional().nullable(),
|
||||||
|
|
||||||
|
// Security & Alerts
|
||||||
|
magnetic_attack: z.boolean().optional().nullable(),
|
||||||
|
realtime_information_flag: z.boolean().optional().nullable(),
|
||||||
|
|
||||||
|
// Flow Measurements
|
||||||
|
current_flow: z.number().optional().nullable(),
|
||||||
|
total_flow_reverse: z.number().optional().nullable(),
|
||||||
|
current_flow_reverse: z.number().optional().nullable(),
|
||||||
|
|
||||||
|
// Protocol Fields
|
||||||
|
l_field: z.string().max(10).optional().nullable(),
|
||||||
|
c_field: z.string().max(10).optional().nullable(),
|
||||||
|
ver: z.string().max(10).optional().nullable(),
|
||||||
|
dev: z.string().max(20).optional().nullable(),
|
||||||
|
ci_field: z.string().max(10).optional().nullable(),
|
||||||
|
|
||||||
|
// Company & Manufacturer Info
|
||||||
|
company_abbreviation: z.string().max(50).optional().nullable(),
|
||||||
|
manufacturer: z.string().max(100).optional().nullable(),
|
||||||
|
|
||||||
|
// Geolocation
|
||||||
|
latitude: z.number().min(-90).max(90).optional().nullable(),
|
||||||
|
longitude: z.number().min(-180).max(180).optional().nullable(),
|
||||||
|
|
||||||
|
// Additional Data
|
||||||
|
data: z.record(z.any()).optional().nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,6 +171,60 @@ export const updateMeterSchema = z.object({
|
|||||||
.datetime({ message: 'Installation date must be a valid ISO date string' })
|
.datetime({ message: 'Installation date must be a valid ISO date string' })
|
||||||
.optional()
|
.optional()
|
||||||
.nullable(),
|
.nullable(),
|
||||||
|
|
||||||
|
// Communication & Network Fields
|
||||||
|
protocol: z.string().max(50).optional().nullable(),
|
||||||
|
mac: z.string().max(50).optional().nullable(),
|
||||||
|
gateway: z.string().max(100).optional().nullable(),
|
||||||
|
network_mode: z.string().max(50).optional().nullable(),
|
||||||
|
phone_id: z.string().max(50).optional().nullable(),
|
||||||
|
phone_model: z.string().max(100).optional().nullable(),
|
||||||
|
phone_name: z.string().max(100).optional().nullable(),
|
||||||
|
|
||||||
|
// Voltage & Power Fields
|
||||||
|
voltage: z.number().optional().nullable(),
|
||||||
|
voltage_rtu: z.number().optional().nullable(),
|
||||||
|
voltage_status: z.string().max(50).optional().nullable(),
|
||||||
|
|
||||||
|
// Signal & Communication Quality
|
||||||
|
signal: z.number().int().optional().nullable(),
|
||||||
|
|
||||||
|
// Status Fields
|
||||||
|
storage_status: z.string().max(50).optional().nullable(),
|
||||||
|
flow_status: z.string().max(50).optional().nullable(),
|
||||||
|
open_status: z.string().max(50).optional().nullable(),
|
||||||
|
actuator_status: z.string().max(50).optional().nullable(),
|
||||||
|
counter_status: z.string().max(50).optional().nullable(),
|
||||||
|
leakage_status: z.string().max(50).optional().nullable(),
|
||||||
|
burst_status: z.string().max(50).optional().nullable(),
|
||||||
|
valid_status: z.string().max(50).optional().nullable(),
|
||||||
|
|
||||||
|
// Security & Alerts
|
||||||
|
magnetic_attack: z.boolean().optional().nullable(),
|
||||||
|
realtime_information_flag: z.boolean().optional().nullable(),
|
||||||
|
|
||||||
|
// Flow Measurements
|
||||||
|
current_flow: z.number().optional().nullable(),
|
||||||
|
total_flow_reverse: z.number().optional().nullable(),
|
||||||
|
current_flow_reverse: z.number().optional().nullable(),
|
||||||
|
|
||||||
|
// Protocol Fields
|
||||||
|
l_field: z.string().max(10).optional().nullable(),
|
||||||
|
c_field: z.string().max(10).optional().nullable(),
|
||||||
|
ver: z.string().max(10).optional().nullable(),
|
||||||
|
dev: z.string().max(20).optional().nullable(),
|
||||||
|
ci_field: z.string().max(10).optional().nullable(),
|
||||||
|
|
||||||
|
// Company & Manufacturer Info
|
||||||
|
company_abbreviation: z.string().max(50).optional().nullable(),
|
||||||
|
manufacturer: z.string().max(100).optional().nullable(),
|
||||||
|
|
||||||
|
// Geolocation
|
||||||
|
latitude: z.number().min(-90).max(90).optional().nullable(),
|
||||||
|
longitude: z.number().min(-180).max(180).optional().nullable(),
|
||||||
|
|
||||||
|
// Additional Data
|
||||||
|
data: z.record(z.any()).optional().nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user