11import cmd
2+ import pandas as pd
3+ import os
4+ import yaml
5+ from typing import List , Dict
26from datetime import datetime , timezone , timedelta
37from influxdb_client import InfluxDBClient , Point , WritePrecision
48from influxdb_client .client .write_api import SYNCHRONOUS
59from dotenv import load_dotenv , dotenv_values
610
11+ CONFIG_FILE = 'config.yaml'
12+
713# Load environment variables
814load_dotenv ()
9- config = dotenv_values (".env" )
15+ env = dotenv_values (".env" )
16+
17+ def load_table_configs () -> Dict [str , List [str ]]:
18+ raw = yaml .safe_load (open (CONFIG_FILE , 'r' ))
19+ table_configs : Dict [str , List [str ]] = {}
20+ for entry in raw ["tables" ]:
21+ name = entry ["name" ]
22+ columns = entry ["columns" ]
23+ if not isinstance (columns , list ):
24+ print (f"Invalid columns for table { name } . Expected a list, got { type (columns )} " )
25+ continue
26+ table_configs [name ] = (columns )
27+ return table_configs
28+
29+ # convert unix timestamp to datetime
30+ def convert_unix_to_datetime (unix_timestamp : int ):
31+ if unix_timestamp < 0 :
32+ print (f"Invalid unix timestamp: { unix_timestamp } " )
33+ return None
34+ return datetime .fromtimestamp (unix_timestamp , tz = timezone .utc )
1035
1136# ask for period of time
1237def askingForPeriod () -> str :
@@ -38,17 +63,30 @@ def insertDataIntoWell(well: int, field: str, data: float, time: datetime, host:
3863 point = Point ("well" ).tag ("well" , well ).field (field , data ).time (time , WritePrecision .NS ).tag ("host" , host )
3964 write_api .write (bucket , org , point )
4065
66+ # ask for file path
67+ def askingForFilePath () -> str :
68+ path = input ("Please enter the file path: " )
69+ if not path :
70+ print ("Invalid file path" )
71+ return None
72+ if not os .path .exists (path ):
73+ print ("File does not exist" )
74+ return None
75+ return path
76+
4177class TelemetryInputCli (cmd .Cmd ):
78+ # load up config file
79+ table_configs = load_table_configs ()
4280 # Set up the CLI
43- url = config .get ('URL' )
44- bucket = config .get ('DB_BUCKET' )
45- org = config .get ('DB_ORG' )
46- user = config .get ('DB_USER' )
47- password = config .get ('DB_PASSWORD' )
48- token = config .get ('DB_TOKEN' )
49- payloadTag = config .get ('PAYLOAD_TAG' )
50- wellTempField = config .get ('WELL_TEMP_FIELD' )
51- wellLuminField = config .get ('WELL_LUMIN_FIELD' )
81+ url = env .get ('URL' )
82+ bucket = env .get ('DB_BUCKET' )
83+ org = env .get ('DB_ORG' )
84+ user = env .get ('DB_USER' )
85+ password = env .get ('DB_PASSWORD' )
86+ token = env .get ('DB_TOKEN' )
87+ payloadTag = env .get ('PAYLOAD_TAG' )
88+ wellTempField = env .get ('WELL_TEMP_FIELD' )
89+ wellLuminField = env .get ('WELL_LUMIN_FIELD' )
5290 client = InfluxDBClient (url = url , token = token , org = org )
5391 write_api = client .write_api (write_options = SYNCHRONOUS )
5492 prompt = '> '
@@ -69,16 +107,34 @@ def do_insert_temp_well(self, arg):
69107 'Insert temperature data into a specific well with specified time'
70108 self .insert_data_into_well (self .wellTempField )
71109
72- # insert humidity data into all wells with specified time
110+ # insert luminosity data into all wells with specified time
73111 def do_insert_lumin_wells (self , arg ):
74- 'Insert luminance data into all wells with specified time'
112+ 'Insert luminosity data into all wells with specified time'
75113 self .insert_data_into_wells (self .wellLuminField )
76114
77- # insert humidity data into a specific well with specified time
115+ # insert luminosity data into a specific well with specified time
78116 def do_insert_lumin_well (self , arg ):
79- 'Insert luminance data into a specific well with specified time'
117+ 'Insert luminosity data into a specific well with specified time'
80118 self .insert_data_into_well (self .wellLuminField )
81119
120+ def do_bulk_insert (self , arg ):
121+ 'Bulk insert data from a CSV file into the specified table'
122+ # print out available option from table_configs
123+ if not self .table_configs :
124+ print ("No tables available for bulk insert." )
125+ return
126+ print ("Available tables for bulk insert:" )
127+ for table in self .table_configs .keys ():
128+ print (f"- { table } " )
129+ table = input ("Please enter the table name: " )
130+ if table not in self .table_configs :
131+ print (f"Table { table } does not exist." )
132+ return
133+ filePath = askingForFilePath ()
134+ if not filePath :
135+ return
136+ self .insert_data_from_df (table , filePath )
137+
82138 # helper function to insert data into all wells
83139 def insert_data_into_wells (self , field ):
84140 period = askingForPeriod ()
@@ -102,6 +158,47 @@ def insert_data_into_well(self, field):
102158 return
103159 insertDataIntoWell (well , field , data , calculatedTime , self .payloadTag , self .write_api , self .bucket , self .org )
104160 print ("Data inserted successfully" )
161+
162+ # bulk insert data into bucket
163+ def insert_data_from_df (self , table :str , filePath :str ):
164+ if not filePath :
165+ return
166+ if filePath .endswith ('.csv' ):
167+ try :
168+ df = pd .read_csv (filePath , usecols = self .table_configs [table ])
169+ except ValueError as e :
170+ print (f"Error reading CSV file: { e } " )
171+ return
172+ else :
173+ print ("Unsupported file format. Please provide a CSV file." )
174+ return
175+ # print out record
176+ print (f"Loading { len (df )} records from { filePath } for table { table } ." )
177+ if df .empty :
178+ print ("No data to insert." )
179+ return
180+ # convert unix timestamp to datetime
181+ if 'timestamp' in df .columns :
182+ df ['timestamp' ] = df ['timestamp' ].apply (lambda x : convert_unix_to_datetime (x ) if pd .notnull (x ) else None )
183+ else :
184+ print ("No timestamp column found in the data." )
185+ return
186+ # insert data into influxdb
187+ if table == self .wellTempField or table == self .wellLuminField :
188+ for index , row in df .iterrows ():
189+ well_num = row .get ('well_num' )
190+ if pd .notnull (well_num ) and 1 <= well_num <= 16 :
191+ time = row .get ('timestamp' )
192+ if time is not None :
193+ data = row .get ('temperature' ) if table == self .wellTempField else row .get ('luminosity' )
194+ if pd .notnull (data ):
195+ insertDataIntoWell (well_num , table , data , time , self .payloadTag , self .write_api , self .bucket , self .org )
196+ else :
197+ print (f"Invalid well number { well_num } at index { index } . Skipping this record." )
198+ else :
199+ print (f"Unsupported table { table } . Only 'temp' and 'lumin' are supported for bulk insert." )
200+ return
201+ print (f"Data from { filePath } inserted into { table } table successfully." )
105202
106203 # helper function to get data from user
107204 def get_data_from_user (self ):
0 commit comments