├── README.md ├── cli_data_extractor.py ├── cli_data_extractor_multiple_times.py └── waitress-rest-api-server.py /README.md: -------------------------------------------------------------------------------- 1 | # Prerequisite 2 | - PI ProcessBook v3.2.3.0 3 | - Anaconda v4.2.9 4 | - Waitress 1.3.1 5 | 6 | # Main function *getting data from PI Server* 7 | - if you want to extract data with .csv, execute 'cli_data_extractor.py'. 8 | - if you want to serve REST API server, execute 'waitress-rest-api-server.py'. -------------------------------------------------------------------------------- /cli_data_extractor.py: -------------------------------------------------------------------------------- 1 | import pythoncom, pywintypes, os 2 | import win32com.client as win32 3 | import numpy as np 4 | 5 | NUM_OF_SAMPLE = 12*24*30*2 6 | SPACE = 5 7 | UNIT = 'm' 8 | END_TIME ='2021-06-26T00:00:00' 9 | DELAY = '' # -20s when end time is * 10 | EXCPT = 'n' # r:reason, n:nan, b:blank 11 | TAG_NAME_IN_RESULT = True 12 | 13 | if EXCPT != 'r' and EXCPT != 'n' and EXCPT != 'b': 14 | raise('excpt type error!') 15 | 16 | # Print iterations progress 17 | def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█', printEnd = "\r"): 18 | """ 19 | Call in a loop to create terminal progress bar 20 | @params: 21 | iteration - Required : current iteration (Int) 22 | total - Required : total iterations (Int) 23 | prefix - Optional : prefix string (Str) 24 | suffix - Optional : suffix string (Str) 25 | decimals - Optional : positive number of decimals in percent complete (Int) 26 | length - Optional : character length of bar (Int) 27 | fill - Optional : bar fill character (Str) 28 | printEnd - Optional : end character (e.g. "\r", "\r\n") (Str) 29 | """ 30 | percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) 31 | filledLength = int(length * iteration // total) 32 | bar = fill * filledLength + '-' * (length - filledLength) 33 | print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = printEnd) 34 | # Print New Line on Complete 35 | if iteration == total: 36 | print() 37 | 38 | server = win32.Dispatch('PISDK.PISDK.1').Servers('POSCOPOWER') 39 | pisdk = win32.gencache.EnsureModule('{0EE075CE-8C31-11D1-BD73-0060B0290178}',0, 1, 1,bForDemand = False) 40 | 41 | point = [] 42 | iter_cnt = 1 43 | err_cnt= 0 44 | reason = set() 45 | 46 | tags = [k for k in os.listdir() if 'tag' in k] 47 | tag =np.array([]) 48 | for key in tags: 49 | tag = np.concatenate((tag,np.loadtxt(key, dtype=str, delimiter=','))) 50 | tag = list(set(tag)) 51 | print(tag) 52 | 53 | for x in tag: 54 | point.append(server.PIPoints(x).Data) 55 | l = len(point) 56 | trends = [] 57 | 58 | printProgressBar(0, l, prefix = 'Progress:', suffix = 'Complete', length = 50) 59 | 60 | for i, p in enumerate(point): 61 | if p is not None: 62 | data2 = pisdk.IPIData2(p) 63 | #print('Extracting Data...') 64 | while True: 65 | try: 66 | results = data2.InterpolatedValues2(END_TIME+DELAY+'-'+str(int(NUM_OF_SAMPLE)*SPACE)+UNIT,END_TIME+DELAY,str(SPACE)+UNIT,asynchStatus=None) 67 | #print('**************************Successful!') 68 | break 69 | except pywintypes.com_error: 70 | #print('Error occured, retrying...') 71 | pass 72 | tmpValue = [] 73 | tmpTime = [] 74 | for v in results: 75 | try: 76 | if i == 0: 77 | t = float(v.TimeStamp.LocalDate.timestamp()) 78 | tmpTime.append(t) 79 | s = str(v.Value) 80 | tmpValue.append(float(s)) 81 | except ValueError: 82 | # if s == 'N RUN' or s == 'NRUN' or s == 'N OPEN' or s == 'NSTART' or s == 'OFF': 83 | if s in ['N RUN', 'NRUN', 'N OPEN', 'NSTART', 'OFF', 'N CLS', 'NO', 'N OPND', 'CLOSE', 'N OPN', 'NOPEND']: 84 | tmpValue.append(0.0) 85 | # elif s == 'RUN' or s == 'OPEN' or s == 'START' or s == 'ON': 86 | elif s in ['RUN', 'OPEN', 'START', 'ON', 'OPENED', 'YES', 'OPEND',]: 87 | tmpValue.append(1.0) 88 | else: 89 | try: 90 | if EXCPT == 'r': 91 | tmpValue.append(s) 92 | else: 93 | tmpValue.append(np.nan) 94 | # tmpValue.append(tmpValue[-1]) 95 | #except IndexError: 96 | # tmpValue.append(0.0) 97 | finally: 98 | err_cnt += 1 99 | reason.add(str(v.Value)) 100 | if i == 0: 101 | #tmpTime.pop() 102 | trends.append(tmpTime) 103 | #tmpValue.pop() 104 | trends.append(tmpValue) 105 | printProgressBar(i + 1, l, prefix = 'Progress:', suffix = 'Complete', length = 50) 106 | 107 | print('Total Error Counter: ', end='') 108 | print(err_cnt) 109 | 110 | print('Reason: ', end='') 111 | print(*reason if reason else '', sep=', ') 112 | 113 | trends = np.array(trends).transpose() 114 | if EXCPT == 'b': 115 | trends = trends[~np.isnan(trends).any(axis=1)] 116 | if TAG_NAME_IN_RESULT: 117 | tag.insert(0,'time') 118 | trends = np.concatenate((np.array(tag).reshape(1,-1),trends),axis=0 ) 119 | 120 | np.savetxt(END_TIME.split()[0].replace('*','crnt').replace(':','')+DELAY+'_'+str(SPACE)+UNIT+'_'+str(int(NUM_OF_SAMPLE))+'_'+EXCPT+'.csv', trends, delimiter=',', fmt='%s') 121 | -------------------------------------------------------------------------------- /cli_data_extractor_multiple_times.py: -------------------------------------------------------------------------------- 1 | import pythoncom, pywintypes, datetime, os 2 | import win32com.client as win32 3 | import numpy as np 4 | 5 | NUM_OF_SAMPLE = 12*10 6 | SPACE = 5 7 | UNIT = 's' 8 | DELAY = '+10m' # -20s when end time is * 9 | EXCPT = 'n' # r:reason, n:nan, b:blank 10 | TAG_NAME_IN_RESULT = True 11 | 12 | if EXCPT != 'r' and EXCPT != 'n' and EXCPT != 'b': 13 | raise('excpt type error!') 14 | 15 | # Print iterations progress 16 | def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█', printEnd = "\r"): 17 | """ 18 | Call in a loop to create terminal progress bar 19 | @params: 20 | iteration - Required : current iteration (Int) 21 | total - Required : total iterations (Int) 22 | prefix - Optional : prefix string (Str) 23 | suffix - Optional : suffix string (Str) 24 | decimals - Optional : positive number of decimals in percent complete (Int) 25 | length - Optional : character length of bar (Int) 26 | fill - Optional : bar fill character (Str) 27 | printEnd - Optional : end character (e.g. "\r", "\r\n") (Str) 28 | """ 29 | percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) 30 | filledLength = int(length * iteration // total) 31 | bar = fill * filledLength + '-' * (length - filledLength) 32 | print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = printEnd) 33 | # Print New Line on Complete 34 | if iteration == total: 35 | print() 36 | 37 | server = win32.Dispatch('PISDK.PISDK.1').Servers('POSCOPOWER') 38 | pisdk = win32.gencache.EnsureModule('{0EE075CE-8C31-11D1-BD73-0060B0290178}',0, 1, 1,bForDemand = False) 39 | 40 | point = [] 41 | iter_cnt = 1 42 | err_cnt= 0 43 | reason = set() 44 | 45 | tags = [k for k in os.listdir() if 'tag' in k] 46 | tag =np.array([]) 47 | for key in tags: 48 | tag = np.concatenate((tag,np.loadtxt(key, dtype=np.str, delimiter=','))) 49 | tag = list(set(tag)) 50 | print(tag) 51 | 52 | refTimes = np.loadtxt('./times.csv', dtype=np.str, delimiter=',') 53 | 54 | tot_trends = [] 55 | 56 | for x in tag: 57 | point.append(server.PIPoints(x).Data) 58 | l = len(point) * len(refTimes) 59 | 60 | printProgressBar(0, l, prefix = 'Progress:', suffix = 'Complete', length = 50) 61 | for j, rt in enumerate(refTimes): 62 | trends = [] 63 | for i, p in enumerate(point): 64 | if p is not None: 65 | data2 = pisdk.IPIData2(p) 66 | #print('Extracting Data...') 67 | while True: 68 | try: 69 | results = data2.InterpolatedValues2(rt+DELAY+'-'+str(int(NUM_OF_SAMPLE)*SPACE)+UNIT,rt+DELAY,str(SPACE)+UNIT,asynchStatus=None) 70 | #print('**************************Successful!') 71 | break 72 | except pywintypes.com_error: 73 | #print('Error occured, retrying...') 74 | pass 75 | tmpValue = [] 76 | tmpTime = [] 77 | for v in results: 78 | try: 79 | if i == 0: 80 | t = float(v.TimeStamp.LocalDate.timestamp()) 81 | tmpTime.append(t) 82 | s = str(v.Value) 83 | tmpValue.append(float(s)) 84 | except ValueError: 85 | if s == 'N RUN' or s == 'NRUN' or s == 'N OPEN' or s == 'NSTART' or s == 'OFF': 86 | tmpValue.append(0.0) 87 | elif s == 'RUN' or s == 'OPEN' or s == 'START' or s == 'ON': 88 | tmpValue.append(1.0) 89 | else: 90 | try: 91 | if EXCPT == 'r': 92 | tmpValue.append(s) 93 | else: 94 | tmpValue.append(np.nan) 95 | # tmpValue.append(tmpValue[-1]) 96 | #except IndexError: 97 | # tmpValue.append(0.0) 98 | finally: 99 | err_cnt += 1 100 | reason.add(str(v.Value)) 101 | if i == 0: 102 | #tmpTime.pop() 103 | trends.append(tmpTime) 104 | #tmpValue.pop() 105 | trends.append(tmpValue) 106 | printProgressBar(j * len(point) + i + 1, l, prefix = 'Progress:', suffix = 'Complete', length = 50) 107 | trends = np.array(trends).transpose() 108 | tot_trends.extend(trends) 109 | 110 | tot_trends = np.array(tot_trends) 111 | 112 | print('Total Error Counter: ', end='') 113 | print(err_cnt) 114 | 115 | print('Reason: ', end='') 116 | print(*reason if reason else '', sep=', ') 117 | 118 | if TAG_NAME_IN_RESULT: 119 | tag.insert(0,'time') 120 | tot_trends = np.concatenate((np.array(tag).reshape(1,-1),tot_trends),axis=0 ) 121 | 122 | if EXCPT == 'b': 123 | tot_trends = tot_trends[~np.isnan(trends).any(axis=1)] 124 | np.savetxt('{}{}.csv'.format(datetime.datetime.now().isoformat('T','seconds').replace(':','-'), EXCPT), tot_trends, delimiter=',', fmt='%s') 125 | -------------------------------------------------------------------------------- /waitress-rest-api-server.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from flask_cors import CORS 3 | from waitress import serve 4 | from flask_restful import reqparse, abort, Api, Resource 5 | 6 | import pythoncom, pywintypes, requests, json, datetime, os 7 | from dateutil.parser import parse 8 | import win32com.client as win32 9 | 10 | app = Flask(__name__) 11 | CORS(app) 12 | api = Api(app) 13 | 14 | class TagsForKeyword(Resource): 15 | def get(self, keyword): 16 | # preventing overhead on server 17 | #if len(keyword) < 4: 18 | # abort(404, error="Keyword '{}' is too short to search.".format(keyword)) 19 | 20 | pythoncom.CoInitialize() 21 | server = win32.Dispatch('PISDK.PISDK').Servers('POSCOPOWER') 22 | result = {} 23 | #print(server.PIPoints('PTB5504').PointAttributes('descriptor').Value) 24 | ptList = server.GetPoints("tag = '"+keyword+"'",None) 25 | 26 | # abort if there are no results. 27 | if ptList.Count == 0: 28 | abort(404, error="No results for Keyword '{}'.".format(keyword)) 29 | 30 | for i in ptList: 31 | result[str(i.Name)] = { 32 | 'descriptor':str(i.PointAttributes('descriptor').Value), 33 | 'value':str(i.Data.Snapshot), 34 | 'engunits':str(i.PointAttributes('engunits').Value), 35 | 'timestamp':str(i.Data.Snapshot.TimeStamp.LocalDate) 36 | } 37 | pythoncom.CoUninitialize() 38 | 39 | return result 40 | 41 | class GroupLiveTags(Resource): 42 | def get(self, tags): 43 | 44 | tags= tags.split(",") 45 | pythoncom.CoInitialize() 46 | server = win32.Dispatch('PISDK.PISDK').Servers('POSCOPOWER') 47 | 48 | result = {} 49 | for tag in tags: 50 | try: 51 | result[tag] = [str(server.PIPoints(tag).Data.Snapshot.TimeStamp.LocalDate), str(server.PIPoints(tag).Data.Snapshot)] 52 | except Exception as e: 53 | abort(404, error="{} with {}".format(repr(e), tag)) 54 | pythoncom.CoUninitialize() 55 | 56 | return result 57 | 58 | class GroupRecordedTags(Resource): 59 | def get(self, tags, end, period, delay): 60 | 61 | tags = tags.split(",") 62 | try: 63 | if end != '*': 64 | end = parse(end) 65 | isnow = False 66 | else: 67 | isnow = True 68 | period = parse(period)-parse('0s') 69 | delay = parse(delay)-parse('0s') 70 | except Exception as e: 71 | abort(404, error="{}".format(repr(e))) 72 | pythoncom.CoInitialize() 73 | server = win32.Dispatch('PISDK.PISDK').Servers('POSCOPOWER') 74 | pisdk = win32.gencache.EnsureModule('{0EE075CE-8C31-11D1-BD73-0060B0290178}',0, 1, 1,bForDemand = False) 75 | result = {} 76 | for tag in tags: 77 | try: 78 | data2 = pisdk.IPIData2(server.PIPoints(tag).Data) 79 | if isnow: 80 | pitmp = data2.RecordedValues(str(end)+'-'+str(period+delay),str(end)+'-'+str(delay),3,"",0,None) 81 | else: 82 | pitmp = data2.RecordedValues(str(end-period-delay),str(end-delay),3,"",0,None) 83 | except Exception as e: 84 | abort(404, error="{}".format(repr(e))) 85 | tmp = [] 86 | for val in pitmp: 87 | v = str(val.Value) 88 | t = str(val.TimeStamp.LocalDate) 89 | tmp.append([t, v]) 90 | result[tag] = tmp 91 | pythoncom.CoUninitialize() 92 | 93 | return result 94 | 95 | class GroupIPRecordedTags(Resource): 96 | def get(self, tags, end, period, delay, freq): 97 | 98 | tags= tags.split(",") 99 | try: 100 | if end != '*': 101 | end = parse(end) 102 | isnow = False 103 | else: 104 | isnow = True 105 | period = parse(period)-parse('0s') 106 | delay = parse(delay)-parse('0s') 107 | except Exception as e: 108 | abort(404, error="{}".format(repr(e))) 109 | pythoncom.CoInitialize() 110 | server = win32.Dispatch('PISDK.PISDK').Servers('POSCOPOWER') 111 | pisdk = win32.gencache.EnsureModule('{0EE075CE-8C31-11D1-BD73-0060B0290178}',0, 1, 1,bForDemand = False) 112 | result = {} 113 | for tag in tags: 114 | try: 115 | data2 = pisdk.IPIData2(server.PIPoints(tag).Data) 116 | if isnow: 117 | pitmp = data2.InterpolatedValues2(str(end)+'-'+str(period+delay),str(end)+'-'+str(delay),freq,asynchStatus=None) 118 | else: 119 | pitmp = data2.InterpolatedValues2(str(end-period-delay),str(end-delay),freq,asynchStatus=None) 120 | except Exception as e: 121 | abort(404, error="{}".format(repr(e))) 122 | tmp = [] 123 | for val in pitmp: 124 | v = str(val.Value) 125 | t = str(val.TimeStamp.LocalDate) 126 | tmp.append([t, v]) 127 | result[tag] = tmp 128 | pythoncom.CoUninitialize() 129 | 130 | return result 131 | 132 | api.add_resource(TagsForKeyword, '/tags-for-keyword/') 133 | api.add_resource(GroupLiveTags, '/group-live-tags/') 134 | api.add_resource(GroupRecordedTags, '/group-recorded-tags////') 135 | api.add_resource(GroupIPRecordedTags, '/group-ip-recorded-tags/////') 136 | 137 | ## Serve using waitress 138 | serve(app, host='me', port=8080) --------------------------------------------------------------------------------