22Sensor discovery module.
33
44Scans the database for all unique sensor names within a time range.
5- Uses adaptive chunking with parallel execution.
5+ Uses adaptive chunking with parallel execution for narrow schema.
6+ For wide schema, uses instant information_schema.columns metadata lookup.
67"""
78
89from __future__ import annotations
1617
1718from . import config
1819from .query_utils import adaptive_query , run_chunks_parallel , PermanentQueryError , quote_table
20+ from .writer import NON_SIGNAL_COLS
1921
2022
2123def discover_sensors (
@@ -24,23 +26,53 @@ def discover_sensors(
2426 chunk_size_days : int = 7 ,
2527 client : Optional [InfluxDBClient3 ] = None ,
2628 show_progress : bool = True ,
29+ schema : str = "narrow" ,
2730) -> List [str ]:
2831 """
2932 Scan the database for ALL unique sensor names within the time range.
3033
31- Uses adaptive chunking with parallel execution to handle server
32- resource limits efficiently.
34+ For ``schema="wide"``, uses an instant ``information_schema.columns`` metadata
35+ lookup (no data scan, no adaptive bisection, ignores time range and chunk params).
36+
37+ For ``schema="narrow"`` (default), uses adaptive chunking with parallel execution
38+ to handle server resource limits efficiently.
3339
3440 Args:
35- start_time: Start of scan range.
36- end_time: End of scan range.
37- chunk_size_days: Days per chunk (default 7).
41+ start_time: Start of scan range (narrow schema only) .
42+ end_time: End of scan range (narrow schema only) .
43+ chunk_size_days: Days per chunk (default 7, narrow schema only ).
3844 client: Ignored (kept for backward compatibility).
39- show_progress: Show progress bar (default True).
45+ show_progress: Show progress bar (default True, narrow schema only).
46+ schema: "narrow" (legacy EAV) or "wide" (one field per signal).
4047
4148 Returns:
4249 Sorted list of unique sensor name strings.
4350 """
51+ db_schema = config .INFLUX_SCHEMA or "iox"
52+ table = config .INFLUX_TABLE or config .INFLUX_DB
53+
54+ if schema == "wide" :
55+ # Instant metadata lookup — no data scan needed
56+ cli = InfluxDBClient3 (
57+ host = config .INFLUX_URL ,
58+ token = config .INFLUX_TOKEN ,
59+ database = config .INFLUX_DB ,
60+ )
61+ sql = (
62+ f"SELECT column_name FROM information_schema.columns "
63+ f"WHERE table_schema = '{ db_schema } ' AND table_name = '{ table } '"
64+ )
65+ result = cli .query (query = sql )
66+ if result .num_rows == 0 :
67+ return []
68+ col = result .column ("column_name" )
69+ return sorted (
70+ v .as_py ()
71+ for v in col
72+ if v .as_py () is not None and v .as_py () not in NON_SIGNAL_COLS
73+ )
74+
75+ # --- narrow (legacy EAV) path ---
4476
4577 def _make_client () -> InfluxDBClient3 :
4678 return InfluxDBClient3 (
@@ -52,21 +84,17 @@ def _make_client() -> InfluxDBClient3:
5284 def _query_distinct (
5385 client : InfluxDBClient3 , t0 : datetime , t1 : datetime ,
5486 ) -> List [str ]:
55- # Ensure safe defaults if config vars are missing or empty
56- schema = config .INFLUX_SCHEMA or "iox"
57- table = config .INFLUX_TABLE or config .INFLUX_DB
58- table_ref = quote_table (schema , table )
59-
87+ table_ref = quote_table (db_schema , table )
6088 sql = f"""
6189 SELECT DISTINCT "signalName"
6290 FROM { table_ref }
6391 WHERE time >= '{ t0 .isoformat ()} Z'
6492 AND time < '{ t1 .isoformat ()} Z'
6593 """
66- table = client .query (query = sql )
67- if table .num_rows == 0 :
94+ tbl = client .query (query = sql )
95+ if tbl .num_rows == 0 :
6896 return []
69- col = table .column ("signalName" )
97+ col = tbl .column ("signalName" )
7098 return [v .as_py () for v in col if v .as_py () is not None ]
7199
72100 def _process_chunk (
0 commit comments