core.py 15 KB

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