core.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. import calendar
  2. import datetime
  3. import os
  4. import re
  5. import sys
  6. import yaml
  7. import time
  8. import requests
  9. import shutil
  10. import tornado.ioloop
  11. import tornado.web
  12. import tornado.autoreload
  13. from shutil import copyfile
  14. from datetime import date
  15. from time import gmtime, strftime
  16. from tornado.escape import json_decode, json_encode, url_escape
  17. from threading import Timer
  18. import subprocess
  19. root = os.path.dirname(__file__)
  20. class RepeatedTimer(object):
  21. def __init__(self, interval, function, *args, **kwargs):
  22. self._timer = None
  23. self.interval = interval
  24. self.function = function
  25. self.args = args
  26. self.kwargs = kwargs
  27. self.is_running = False
  28. self.start()
  29. def _run(self):
  30. self.is_running = False
  31. self.start()
  32. self.function(*self.args, **self.kwargs)
  33. def start(self):
  34. if not self.is_running:
  35. self._timer = Timer(self.interval, self._run)
  36. self._timer.start()
  37. self.is_running = True
  38. def stop(self):
  39. self._timer.cancel()
  40. self.is_running = False
  41. def setInterval(self, interval):
  42. self.interval = interval
  43. months = {
  44. 'Jan' : 1,
  45. 'Feb' : 2,
  46. 'Mar' : 3,
  47. 'Apr' : 4,
  48. 'May' : 5,
  49. 'Jun' : 6,
  50. 'Jul' : 7,
  51. 'Aug' : 8,
  52. 'Sep' : 9,
  53. 'Oct' : 10,
  54. 'Nov' : 11,
  55. 'Dec' : 12
  56. }
  57. def fetchDataADEI():
  58. with open("varname.yaml", 'r') as stream:
  59. try:
  60. varname = yaml.load(stream)
  61. except yaml.YAMLError as exc:
  62. print(exc)
  63. if varname is None:
  64. print("Error: Empty varname file.")
  65. return
  66. cache_data = {}
  67. curtime = int(time.time())
  68. time_image_range = str((curtime-3600)) + "-" + str(curtime)
  69. time_range = "-1"
  70. for param in varname:
  71. dest = os.environ["BORA_ADEI_SERVER"] + 'services/getdata.php'
  72. url = dest + "?" + varname[param] + "&window=" + time_range
  73. data = requests.get(url,
  74. auth=(os.environ["BORA_ADEI_USERNAME"],
  75. os.environ["BORA_ADEI_PASSWORD"])).content
  76. tmp_data = data.splitlines()[-1]
  77. if "ERROR" in tmp_data:
  78. continue
  79. last_value = tmp_data.split(",")[-1].strip()
  80. first_value = tmp_data.split(",")[-2].strip()
  81. try:
  82. test_x = float(last_value)
  83. except ValueError:
  84. last_value = ""
  85. try:
  86. time_buffer = first_value.split("-")
  87. time_buffer[1] = str(months[time_buffer[1]])
  88. first_value = "-".join(time_buffer)
  89. first_ts = calendar.timegm(datetime.datetime.strptime(first_value, "%d-%m-%y %H:%M:%S.%f").timetuple())
  90. except:
  91. first_ts = ""
  92. cache_data[param] = {'timestamp': first_ts, 'value': last_value}
  93. current_timestamp = strftime("%Y-%m-%d %H:%M:%S")
  94. cache_data['time'] = current_timestamp
  95. fetch_image_url = (os.environ["BORA_ADEI_SERVER"] + 'services/getimage.php' + "?" +
  96. varname[param] + "&window=" + time_image_range +
  97. "&frame_width=600&frame_height=400")
  98. image = requests.get(fetch_image_url,
  99. auth=(os.environ['BORA_ADEI_USERNAME'],
  100. os.environ['BORA_ADEI_PASSWORD']))
  101. if not os.path.isdir("./bora/static/trends/"):
  102. subprocess.call(["mkdir", "-p", "./bora/static/trends"])
  103. with open("bora/static/trends/" + param + ".png", 'wb') as handle:
  104. for chunk in image.iter_content():
  105. handle.write(chunk)
  106. with open("./bora/.tmp.yaml", 'w') as stream_tmp:
  107. stream_tmp.write(yaml.dump(cache_data, default_flow_style=False))
  108. src_file = os.getcwd() + "/bora/.tmp.yaml"
  109. dst_file = os.getcwd() + "/bora/cache.yaml"
  110. shutil.copy(src_file, dst_file)
  111. class BaseHandler(tornado.web.RequestHandler):
  112. def get_current(self):
  113. return self.get_secure_cookie("user")
  114. class ListHandler(tornado.web.RequestHandler):
  115. def get(self):
  116. with open("./bora/cache.yaml", 'r') as stream:
  117. try:
  118. response = yaml.load(stream)
  119. except yaml.YAMLError as exc:
  120. print(exc)
  121. if response is None:
  122. response = {"error": "No data entry."}
  123. self.write(response)
  124. class StartHandler(tornado.web.RequestHandler):
  125. def get(self):
  126. print "Start fetchData"
  127. rt.start()
  128. class StopHandler(tornado.web.RequestHandler):
  129. def get(self):
  130. print "Stop fetchData"
  131. rt.stop()
  132. class SetTimerHandler(tornado.web.RequestHandler):
  133. def get(self, duration):
  134. print "Set interval"
  135. rt.setInterval(float(duration))
  136. class DesignerHandler(tornado.web.RequestHandler):
  137. def get(self):
  138. print "In designer mode."
  139. with open("./bora/cache.yaml", 'r') as stream:
  140. try:
  141. cache_data = yaml.load(stream)
  142. except yaml.YAMLError as exc:
  143. print(exc)
  144. with open("style.yaml", 'r') as stream:
  145. try:
  146. style_data = yaml.load(stream)
  147. except yaml.YAMLError as exc:
  148. print(exc)
  149. if style_data:
  150. index_data = list(set(cache_data) | set(style_data))
  151. else:
  152. index_data = cache_data
  153. if index_data is not None:
  154. index_data = sorted(index_data)
  155. data = {
  156. "cache": cache_data,
  157. "style": style_data,
  158. "index": index_data,
  159. }
  160. data["title"] = os.environ["BORA_TITLE"]
  161. self.render('designer.html', data=data)
  162. class VersionHandler(tornado.web.RequestHandler):
  163. def get(self):
  164. response = {'version': '1.0.0'}
  165. self.write(response)
  166. class BackupHandler(tornado.web.RequestHandler):
  167. def post(self):
  168. backup_dst = os.getcwd() + "/backup/"
  169. fname = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
  170. os.makedirs(backup_dst + fname)
  171. copyfile("varname.yaml", backup_dst +
  172. fname + "/varname.yaml")
  173. copyfile("style.yaml", backup_dst +
  174. fname + "/style.yaml")
  175. class SaveHandler(tornado.web.RequestHandler):
  176. def post(self):
  177. json_obj = json_decode(self.request.body)
  178. with open("style.yaml", 'w') as output:
  179. output.write(yaml.safe_dump(json_obj, encoding='utf-8',
  180. allow_unicode=True, default_flow_style=False))
  181. response = {"success": "Data entry inserted."}
  182. class StatusHandler(tornado.web.RequestHandler):
  183. def get(self):
  184. print "In status mode."
  185. with open("style.yaml", 'r') as stream:
  186. try:
  187. style_data = yaml.load(stream)
  188. except yaml.YAMLError as exc:
  189. print(exc)
  190. with open("varname.yaml", 'r') as vstream:
  191. try:
  192. varname_data = yaml.load(vstream)
  193. except yaml.YAMLError as exc:
  194. print(exc)
  195. if not os.path.isfile("./bora/cache.yaml"):
  196. print "BORA is loading data, please refresh the page again in a moment."
  197. open("cache.yaml","w")
  198. with open("./bora/cache.yaml", 'r') as vstream:
  199. try:
  200. cache_data = yaml.load(vstream)
  201. except yaml.YAMLError as exc:
  202. print(exc)
  203. data = {
  204. "style": style_data,
  205. "varname": varname_data,
  206. "cache": cache_data
  207. }
  208. data["title"] = os.environ["BORA_TITLE"]
  209. data["server"] = os.environ["BORA_ADEI_SERVER"]
  210. self.render('status.html', data=data)
  211. class UpdateHandler(tornado.web.RequestHandler):
  212. def get(self):
  213. print "Update Sensor Definition"
  214. new_data = {}
  215. rt.stop()
  216. with open("varname.yaml", 'r') as stream:
  217. try:
  218. cache_data = yaml.load(stream)
  219. except yaml.YAMLError as exc:
  220. print(exc)
  221. for item in cache_data:
  222. tmp_data = cache_data[item]
  223. tmp_str = []
  224. tmp_store = []
  225. for adei_unit in tmp_data.split("&"):
  226. lhs, rhs = adei_unit.split("=")
  227. if lhs == "db_mask":
  228. tmp_str.append("db_mask=all")
  229. continue
  230. elif lhs == "db_server":
  231. db_server = rhs
  232. tmp_str.append(adei_unit)
  233. tmp_store.append(adei_unit)
  234. tmp_str.append("window=-1")
  235. query = "&".join(tmp_str)
  236. dest = os.environ["BORA_ADEI_SERVER"] + 'services/getdata.php'
  237. url = dest + "?" + query
  238. data = requests.get(url, auth=(os.environ["BORA_ADEI_USERNAME"],
  239. os.environ["BORA_ADEI_PASSWORD"]))
  240. cr = data.content
  241. cr = cr.split(",")
  242. match_token = item
  243. if db_server != "lara" and db_server != "hiu":
  244. # parameter name stored in ADEI with '-IST_Val' suffix
  245. if "MOD" in item:
  246. match_token = item + "-MODUS_Val"
  247. elif "GRA" in item:
  248. match_token = item + "-GRAD_Val"
  249. elif "RPO" in item:
  250. match_token = item + "-ZUST_Val"
  251. elif "VYS" in item:
  252. match_token = item + "-ZUST_Val"
  253. elif "MSS" in item:
  254. match_token = item + "_Val"
  255. else:
  256. match_token = item + "-IST_Val"
  257. db_mask = None
  258. for i, iter_item in enumerate(cr):
  259. if match_token == iter_item.strip():
  260. db_mask = i - 1
  261. if db_mask is None:
  262. continue
  263. tmp_store.append("db_mask="+str(db_mask))
  264. new_data[item] = "&".join(tmp_store)
  265. with open("varname.yaml", 'w') as output:
  266. output.write(yaml.dump(new_data, default_flow_style=False))
  267. response = {"success": "Data entry inserted."}
  268. rt.start()
  269. class AdeiKatrinHandler(tornado.web.RequestHandler):
  270. def get(self, **params):
  271. sensor_name = str(params["sensor_name"])
  272. """
  273. {'db_group': u'320_KRY_Kryo_4K_CurLead',
  274. 'db_name': u'ControlSystem_CPS',
  275. 'sensor_name': u'320-RTP-8-1103',
  276. 'db_server': u'cscps',
  277. 'control_group': u'320_KRY_Kryo_3K'}
  278. """
  279. dest = os.environ["BORA_ADEI_SERVER"] + 'services/getdata.php'
  280. query_cmds = []
  281. query_cmds.append("db_server="+str(params['db_server']))
  282. query_cmds.append("db_name="+str(params['db_name']))
  283. query_cmds.append("db_group="+str(params['db_group']))
  284. query_cmds.append("db_mask=all")
  285. query_cmds.append("window=-1")
  286. query = "&".join(query_cmds)
  287. url = dest + "?" + query
  288. # get the db_masks
  289. # store the query command in varname
  290. data = requests.get(
  291. url,
  292. auth=(os.environ["BORA_ADEI_USERNAME"],
  293. os.environ["BORA_ADEI_PASSWORD"])
  294. )
  295. cr = data.content
  296. cr = cr.splitlines()
  297. cr = ",".join(cr)
  298. cr = cr.split(",")
  299. # handling the inconsistency on naming convention
  300. match_token = params['sensor_name']
  301. if (params["db_server"] != "lara" and params["db_server"] != "hiu" and
  302. params["db_server"] != "safety-first"):
  303. # parameter name stored in ADEI with '-IST_Val' suffix
  304. if "MOD" in params['sensor_name']:
  305. match_token = params['sensor_name'] + "-MODUS_Val"
  306. elif "GRA" in params['sensor_name']:
  307. match_token = params['sensor_name'] + "-GRAD_Val"
  308. elif "RPO" in params['sensor_name']:
  309. match_token = params['sensor_name'] + "-ZUST_Val"
  310. elif "VYS" in params['sensor_name']:
  311. match_token = params['sensor_name'] + "-ZUST_Val"
  312. elif "HVS" in params['sensor_name']:
  313. match_token = params['sensor_name'] + "-ZUST_Val"
  314. elif "VAO" in params['sensor_name']:
  315. match_token = params['sensor_name'] + "-ZUST_Val"
  316. elif "MSS" in params['sensor_name']:
  317. match_token = params['sensor_name'] + "_Val"
  318. else:
  319. match_token = params['sensor_name'] + "-IST_Val"
  320. db_mask = None
  321. for i, item in enumerate(cr):
  322. if "[" and "]" in item.strip():
  323. lhs = re.match(r"[^[]*\[([^]]*)\]", item.strip()).groups()[0]
  324. if lhs == params['sensor_name']:
  325. db_mask = i - 1
  326. else:
  327. if item.strip() == match_token:
  328. db_mask = i - 1
  329. if db_mask is None:
  330. response = {"Error": "Cannot find variable on ADEI server."}
  331. self.write(response)
  332. return
  333. query_cmds = []
  334. query_cmds.append("db_server="+str(params['db_server']))
  335. query_cmds.append("db_name="+str(params['db_name']))
  336. query_cmds.append("db_group="+str(params['db_group']))
  337. query_cmds.append("db_mask="+str(db_mask))
  338. query = "&".join(query_cmds)
  339. # column name available
  340. # store in yaml file
  341. with open("varname.yaml", 'r') as stream:
  342. try:
  343. cache_data = yaml.load(stream)
  344. except yaml.YAMLError as exc:
  345. print(exc)
  346. if cache_data is None:
  347. cache_data = {}
  348. cache_data[sensor_name] = query
  349. else:
  350. if sensor_name not in cache_data:
  351. cache_data[sensor_name] = query
  352. else:
  353. response = {"Error":
  354. "Variable already available in varname file."}
  355. self.write(response)
  356. return
  357. with open("varname.yaml", 'w') as output:
  358. output.write(yaml.dump(cache_data, default_flow_style=False))
  359. response = {"success": "Data entry inserted."}
  360. self.write(response)
  361. class GetDataHandler(tornado.web.RequestHandler):
  362. def get(self):
  363. cache_data = None
  364. with open("./bora/cache.yaml", 'r') as stream:
  365. try:
  366. cache_data = yaml.load(stream)
  367. except yaml.YAMLError as exc:
  368. print(exc)
  369. if cache_data is None:
  370. cache_data = {}
  371. self.write(cache_data)
  372. print "Running..."
  373. rt = RepeatedTimer(int(os.environ["BORA_POLLING"]), fetchDataADEI)
  374. application = tornado.web.Application([
  375. (r"/"+os.environ["BORA_TITLE"].lower()+"/version/?", VersionHandler),
  376. (r"/"+os.environ["BORA_TITLE"].lower()+"/list/?", ListHandler),
  377. (r"/"+os.environ["BORA_TITLE"].lower()+"/start/?", StartHandler),
  378. (r"/"+os.environ["BORA_TITLE"].lower()+"/backup/?", BackupHandler),
  379. (r"/"+os.environ["BORA_TITLE"].lower()+"/stop/?", StopHandler),
  380. (r"/"+os.environ["BORA_TITLE"].lower()+"/designer/?", DesignerHandler),
  381. (r"/"+os.environ["BORA_TITLE"].lower()+"/status/?", StatusHandler),
  382. (r"/"+os.environ["BORA_TITLE"].lower()+"/save/?", SaveHandler),
  383. (r"/"+os.environ["BORA_TITLE"].lower()+"/update/?", UpdateHandler),
  384. (r"/"+os.environ["BORA_TITLE"].lower()+"/getdata/?", GetDataHandler),
  385. (r"/"+os.environ["BORA_TITLE"].lower()+"/timer/(?P<duration>[^\/]+)/?",
  386. SetTimerHandler),
  387. (r"/"+os.environ["BORA_TITLE"].lower()+"/add/(?P<db_server>[^\/]+)/?"
  388. "(?P<db_name>[^\/]+)/?(?P<db_group>[^\/]+)/?(?P<sensor_name>[^\/]+)?",
  389. AdeiKatrinHandler)
  390. ], debug=True, static_path=os.path.join(root, 'static'),
  391. cookie_secret='L8LwECiNRxq2N0N2eGxx9MZlrpmuMEimlydNX/vt1LM=')
  392. if __name__ == "__main__":
  393. application.listen(int(os.environ["BORA_PORT"]))
  394. tornado.autoreload.start()
  395. tornado.ioloop.IOLoop.instance().start()