Merge pull request #1 in POCLOUD/tag-server from MySQL to master
MySQL and SQLite working * commit '667f6540773b6a556171c20a16996b32d334fc05': Able to switch back and forth between MySQL and SQLite Moved location to /root/tagserver MySQL working, need to retro SQLite Converted to CoffeeScript, data in MySQL Added connect statement to connect to db before trying to INSERT reading tags from mysql and writing values to mysql added Tag classes for MySQL and SQLite Updated gitIgnore
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
*.pyc
|
||||
*/bower_components/*
|
||||
*/node_modules/*
|
||||
*/node_modules/*
|
||||
*.log
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#! /bin/sh
|
||||
# /etc/init.d/loggers
|
||||
# /etc/init.d/tagserver
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: loggers
|
||||
# Provides: tagserver
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
@@ -17,22 +17,19 @@
|
||||
case "$1" in
|
||||
start)
|
||||
echo "Starting loggers"
|
||||
kill -9 $(cat /root/solar_ww.pid)
|
||||
kill -9 $(cat /root/tagserver.pid)
|
||||
# run application you want to start
|
||||
#python /home/poconsole/src/dataLogger/alarmLogger.py &
|
||||
#python /home/poconsole/src/dataLogger/dataLogger.py &
|
||||
/usr/bin/python /home/poconsole/tagserver/python/tagserver_SQLite.py > /dev/null 2>&1 & echo $! > "/root/tagserver.pid"
|
||||
/usr/bin/python /root/tagserver/python/tagserver_SQLite.py > /dev/null 2>&1 & echo $! > "/root/tagserver.pid"
|
||||
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping loggers"
|
||||
# kill application you want to stop
|
||||
#killall python
|
||||
kill -9 $(cat /root/tagserver.pid)
|
||||
|
||||
;;
|
||||
*)
|
||||
echo "Usage: /etc/init.d/loggers {start|stop}"
|
||||
echo "Usage: /etc/init.d/tagserver {start|stop}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
18
python/mysql_cfg.pickle
Normal file
18
python/mysql_cfg.pickle
Normal file
@@ -0,0 +1,18 @@
|
||||
(dp0
|
||||
S'host'
|
||||
p1
|
||||
S'127.0.0.1'
|
||||
p2
|
||||
sS'password'
|
||||
p3
|
||||
S'henrypump'
|
||||
p4
|
||||
sS'user'
|
||||
p5
|
||||
S'website'
|
||||
p6
|
||||
sS'database'
|
||||
p7
|
||||
S'poconsole'
|
||||
p8
|
||||
s.
|
||||
11
python/pickle_mysql_config.py
Normal file
11
python/pickle_mysql_config.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import pickle
|
||||
|
||||
mysql_cfg = {
|
||||
'host':'127.0.0.1',
|
||||
'user':'website',
|
||||
'password':'henrypump',
|
||||
'database':'poconsole'
|
||||
}
|
||||
|
||||
with open('mysql_cfg.pickle', 'wb') as pickleconfig:
|
||||
pickle.dump(mysql_cfg, pickleconfig)
|
||||
@@ -1 +1 @@
|
||||
pycomm.ab_comm.clx WARNING 2016-01-25 14:45:25,488 (5, 'forward_close returned False')
|
||||
pycomm.cip.cip_base WARNING 2016-04-07 16:14:59,861 (5, 'forward_close returned False')
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
88
python/tag_mysql.py
Normal file
88
python/tag_mysql.py
Normal file
@@ -0,0 +1,88 @@
|
||||
#! /usr/bin/python
|
||||
|
||||
from datetime import datetime
|
||||
import time
|
||||
import mysql.connector as mysqlcon
|
||||
from pycomm.ab_comm.clx import Driver as ClxDriver
|
||||
import micro800 as u800
|
||||
import traceback
|
||||
import pickle
|
||||
|
||||
with open('/root/tagserver/python/mysql_cfg.pickle', 'rb') as cfgFile:
|
||||
mysql_cfg = pickle.load(cfgFile)
|
||||
con = mysqlcon.connect(**mysql_cfg)
|
||||
|
||||
|
||||
|
||||
def readTag(addr, tag):
|
||||
time.sleep(0.01)
|
||||
c = ClxDriver()
|
||||
if c.open(addr):
|
||||
try:
|
||||
v = c.read_tag(tag)
|
||||
# print(v)
|
||||
return v
|
||||
except Exception:
|
||||
print("ERROR RETRIEVING TAG: {}".format(tag))
|
||||
err = c.get_status()
|
||||
c.close()
|
||||
print traceback.print_exc()
|
||||
pass
|
||||
c.close()
|
||||
|
||||
class Tag():
|
||||
global readTag, con, PLC_IP_ADDRESS
|
||||
|
||||
def __init__(self, name, tag, db_id, data_type, change_threshold, guarantee_sec, mapFn=None, plc_type='CLX', plc_ip_address='192.168.1.10'):
|
||||
self.name = str(name)
|
||||
self.tag = str(tag)
|
||||
self.data_type = str(data_type)
|
||||
self.value = None
|
||||
self.last_value = None
|
||||
self.guarantee_sec = guarantee_sec
|
||||
self.chg_threshold = change_threshold
|
||||
self.last_send_time = 0
|
||||
self.mapFn = mapFn
|
||||
self.plc_type = plc_type
|
||||
self.readFn = readTag
|
||||
self.db_id = db_id
|
||||
if self.plc_type == "u800":
|
||||
self.readFn = u800.readTag
|
||||
self.plc_ip_address = plc_ip_address
|
||||
|
||||
def read(self, forceSend):
|
||||
writeToDB = False
|
||||
if self.tag:
|
||||
v = self.readFn(self.plc_ip_address, self.tag)
|
||||
if v:
|
||||
if self.data_type == 'BOOL' or self.data_type == 'STRING':
|
||||
val = v[0]
|
||||
if self.mapFn:
|
||||
val = self.mapFn[val]
|
||||
if (self.last_send_time == 0) or (self.value is None) or not (self.value == val) or ((time.time() - self.last_send_time) > self.guarantee_sec) or (forceSend):
|
||||
self.last_value = self.value
|
||||
self.value = val
|
||||
writeToDB = True
|
||||
else:
|
||||
writeToDB = False
|
||||
else:
|
||||
if (self.last_send_time == 0) or (self.value is None) or (abs(self.value - v[0]) > self.chg_threshold) or ((time.time() - self.last_send_time) > self.guarantee_sec) or (forceSend):
|
||||
self.last_value = self.value
|
||||
self.value = v[0]
|
||||
writeToDB = True
|
||||
else:
|
||||
writeToDB = False
|
||||
if writeToDB:
|
||||
self.sendToDB()
|
||||
|
||||
def sendToDB(self):
|
||||
# TODO: Datetime
|
||||
query = "INSERT INTO poconsole.tag_vals (dtime, tagID, val) VALUES ('{}', '{}', {})".format(time.strftime('%Y-%m-%d %H:%M:%S'), self.db_id, self.value)
|
||||
self.last_send_time = time.time()
|
||||
print query
|
||||
# TODO: CHECK ON THIS LOGIC -- with con:
|
||||
con.connect()
|
||||
cur = con.cursor()
|
||||
cur.execute(query)
|
||||
con.commit()
|
||||
cur.close()
|
||||
82
python/tag_sqlite.py
Normal file
82
python/tag_sqlite.py
Normal file
@@ -0,0 +1,82 @@
|
||||
#! /usr/bin/python
|
||||
from datetime import datetime
|
||||
import time
|
||||
import sqlite3 as lite
|
||||
from pycomm.ab_comm.clx import Driver as ClxDriver
|
||||
import micro800 as u800
|
||||
import traceback
|
||||
import pickle
|
||||
|
||||
con = lite.connect("/mnt/usb/data.db")
|
||||
# con = lite.connect("/Users/patrickjmcd/Desktop/data.db")
|
||||
|
||||
|
||||
def readTag(addr, tag):
|
||||
time.sleep(0.01)
|
||||
c = ClxDriver()
|
||||
if c.open(addr):
|
||||
try:
|
||||
v = c.read_tag(tag)
|
||||
return v
|
||||
except Exception:
|
||||
print("ERROR RETRIEVING TAG: {} at {}".format(tag, addr))
|
||||
err = c.get_status()
|
||||
c.close()
|
||||
print err
|
||||
pass
|
||||
c.close()
|
||||
|
||||
class Tag():
|
||||
global readTag, con
|
||||
|
||||
def __init__(self, name, tag, db_id, data_type, change_threshold, guarantee_sec, mapFn=None, plc_type='CLK', plc_ip_address='192.168.1.10'):
|
||||
self.name = name
|
||||
self.tag = tag
|
||||
self.data_type = data_type
|
||||
self.value = None
|
||||
self.last_value = None
|
||||
self.guarantee_sec = guarantee_sec
|
||||
self.chg_threshold = change_threshold
|
||||
self.last_send_time = 0
|
||||
self.mapFn = mapFn
|
||||
self.plc_type = plc_type
|
||||
self.readFn = readTag
|
||||
self.db_id = db_id
|
||||
if self.plc_type == "u800":
|
||||
self.readFn = u800.readTag
|
||||
self.plc_ip_address = plc_ip_address
|
||||
|
||||
def read(self, forceSend):
|
||||
writeToDB = False
|
||||
if self.tag:
|
||||
v = self.readFn(str(self.plc_ip_address), str(self.tag))
|
||||
if v:
|
||||
if self.data_type == 'BOOL' or self.data_type == 'STRING':
|
||||
val = v[0]
|
||||
if self.mapFn:
|
||||
val = self.mapFn[val]
|
||||
if (self.last_send_time == 0) or (self.value is None) or not (self.value == val) or ((time.time() - self.last_send_time) > self.guarantee_sec) or (forceSend):
|
||||
self.last_value = self.value
|
||||
self.value = val
|
||||
writeToDB = True
|
||||
else:
|
||||
writeToDB = False
|
||||
else:
|
||||
if (self.last_send_time == 0) or (self.value is None) or (abs(self.value - v[0]) > self.chg_threshold) or ((time.time() - self.last_send_time) > self.guarantee_sec) or (forceSend):
|
||||
self.last_value = self.value
|
||||
self.value = v[0]
|
||||
writeToDB = True
|
||||
else:
|
||||
writeToDB = False
|
||||
if writeToDB:
|
||||
self.sendToDB()
|
||||
|
||||
def sendToDB(self):
|
||||
query = "INSERT INTO tag_vals (dtime, tagID, val) VALUES ({}, '{}', {})".format(time.time(), self.db_id, self.value)
|
||||
self.last_send_time = time.time()
|
||||
print query
|
||||
with con:
|
||||
cur = con.cursor()
|
||||
cur.execute(query)
|
||||
con.commit()
|
||||
cur.close()
|
||||
@@ -1,70 +1,94 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Created on Dec 8, 2015
|
||||
|
||||
MySQL Tag Server
|
||||
Created on April 7, 2016
|
||||
@author: Patrick McDonagh
|
||||
@description: Continuously loops through a list of tags to store values from a PLC into a MySQL database
|
||||
'''
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
import sys
|
||||
from random import randint
|
||||
import mysql.connector as mysqlcon
|
||||
import pickle
|
||||
from tag_mysql import Tag
|
||||
import traceback
|
||||
import time
|
||||
import MySQLdb
|
||||
import tuxeip
|
||||
|
||||
|
||||
#TUXEIP Connection to PLC
|
||||
from tuxeip import TuxEIP, LGX, LGX_REAL
|
||||
|
||||
with open('/root/tagserver/python/mysql_cfg.pickle', 'rb') as pickleconfig:
|
||||
mysql_cfg = pickle.load(pickleconfig)
|
||||
|
||||
if mysql_cfg:
|
||||
db = mysqlcon.connect(**mysql_cfg)
|
||||
|
||||
tag_store = {}
|
||||
configProperties = {}
|
||||
|
||||
def main():
|
||||
|
||||
db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="TagData")
|
||||
db.connect()
|
||||
cur = db.cursor()
|
||||
query = "SELECT * FROM TagData.tags WHERE deleted = 0;"
|
||||
query = "SELECT * FROM tags WHERE class = 5 AND deleted = 0"
|
||||
cur.execute(query)
|
||||
tags = cur.fetchall()
|
||||
# ((1L, 'DC_Bus_Voltage', datetime.datetime(2015, 12, 8, 16, 2, 32), 'V', 0L), (2L, 'Output_Frequency', datetime.datetime(2015, 12, 8, 16, 31, 12), 'Hz', 0L))
|
||||
db.commit()
|
||||
db.close()
|
||||
print tags
|
||||
# [(1, u'Century Counter Up', 5, u'Century_Counter_Up', u'REAL', 10.0, 3600, None, 0)]
|
||||
db.disconnect()
|
||||
|
||||
PLC_IP_ADDRESS = "10.10.10.3" # MAKE THIS A db VALUE
|
||||
scan_rate = 10
|
||||
|
||||
tagList = [];
|
||||
if len(tags) > 0:
|
||||
for t in tags:
|
||||
tagList.append({"id":int(t[0]), "name":t[1], "val":None, "lastVal":None});
|
||||
configObj = {}
|
||||
db.connect()
|
||||
cur = db.cursor()
|
||||
query = "SELECT parameter, val FROM config GROUP BY parameter;"
|
||||
cur.execute(query)
|
||||
config = cur.fetchall()
|
||||
db.disconnect()
|
||||
for x in config:
|
||||
configObj[x[0]] = x[1]
|
||||
|
||||
try:
|
||||
tux = TuxEIP(libpath="/usr/lib/libtuxeip.so")
|
||||
sess = tux.OpenSession(PLC_IP_ADDRESS)
|
||||
reg = tux.RegisterSession(sess)
|
||||
conn = tux.ConnectPLCOverCNET(sess, LGX, 1, 100, 123, randint(0,9999), 123, 321, 100, 5000, 1, '01')
|
||||
configProperties['PLC_IP_ADDRESS'] = str(configObj['ip_address'])
|
||||
print("FYI, using PLC IP Address from the database {0}".format(configProperties['PLC_IP_ADDRESS']))
|
||||
except KeyError:
|
||||
print("FYI, there is no PLC IP Address stored in the database, defaulting to 192.168.1.10")
|
||||
configProperties['PLC_IP_ADDRESS'] = "192.168.1.10"
|
||||
|
||||
while True:
|
||||
for r in tagList:
|
||||
r["val"] = tux.ReadLGXDataAsFloat(sess, conn, r['name'], 1)[0]
|
||||
print("{0} - {1}".format(r["name"], r["val"]))
|
||||
if not r["val"] == r["lastVal"]:
|
||||
db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="TagData")
|
||||
cur = db.cursor()
|
||||
aQuery = """INSERT INTO TagData.values (tagID, val) VALUES ('%d', '%f');"""%(r["id"], float(r["val"]))
|
||||
print(aQuery)
|
||||
storeVal = cur.execute(aQuery)
|
||||
db.commit()
|
||||
db.close()
|
||||
r["lastVal"] = r["val"]
|
||||
try:
|
||||
configProperties['plc_type'] = str(configObj['plc_type'])
|
||||
print("FYI, using PLC Type from the database {0}".format(configProperties['plc_type']))
|
||||
except KeyError:
|
||||
print("FYI, there is no PLC Type stored in the database, defaulting to CLX")
|
||||
configProperties['plc_type'] = "CLX"
|
||||
|
||||
try:
|
||||
configProperties['scan_rate'] = int(configObj['scan_rate'])
|
||||
print("FYI, using Scan Rate from the database {0}".format(configProperties['scan_rate']))
|
||||
except KeyError:
|
||||
print("FYI, there is no Scan Rate stored in the database, defaulting to 10 seconds")
|
||||
configProperties['scan_rate'] = 10
|
||||
|
||||
try:
|
||||
sa_test = str(configObj['save_all'])
|
||||
if sa_test == "true":
|
||||
configProperties['save_all'] = True
|
||||
else:
|
||||
configProperties['save_all'] = False
|
||||
print("FYI, value for save_all is {0}".format(configProperties['save_all']))
|
||||
except KeyError:
|
||||
print("FYI, there is no save_all value stored in the database, using False")
|
||||
configProperties['save_all'] = False
|
||||
|
||||
|
||||
|
||||
|
||||
for t in tags:
|
||||
tag_store[t[1]] = Tag(t[1], t[3], t[0], t[5], t[6], t[7], mapFn=t[8], plc_type=configProperties['plc_type'], plc_ip_address=configProperties['PLC_IP_ADDRESS'])
|
||||
|
||||
|
||||
while True:
|
||||
for tag in tag_store:
|
||||
try:
|
||||
tag_store[tag].read(configProperties['save_all'])
|
||||
except:
|
||||
print("ERROR EVALUATING {}".format(tag))
|
||||
traceback.print_exc()
|
||||
time.sleep(configProperties['scan_rate'])
|
||||
|
||||
time.sleep(10)
|
||||
except Exception as err:
|
||||
print err
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -8,125 +8,87 @@ Created on Dec 8, 2015
|
||||
|
||||
import time
|
||||
import sqlite3 as lite
|
||||
from pycomm.ab_comm.clx import Driver as ClxDriver
|
||||
import micro800 as u800
|
||||
import logging
|
||||
from tag_sqlite import Tag
|
||||
import traceback
|
||||
|
||||
# con = lite.connect("/usr/db/data.db")
|
||||
con = lite.connect('/mnt/usb/data.db')
|
||||
|
||||
configProperties = {}
|
||||
|
||||
def readTag(addr, tag):
|
||||
logging.basicConfig(
|
||||
filename="ClxDriver.log",
|
||||
format="%(levelname)-10s %(asctime)s %(message)s",
|
||||
level=logging.DEBUG
|
||||
)
|
||||
c = ClxDriver()
|
||||
|
||||
if c.open(addr):
|
||||
try:
|
||||
v = c.read_tag(tag)
|
||||
# print(v)
|
||||
return v
|
||||
except Exception as e:
|
||||
err = c.get_status()
|
||||
c.close()
|
||||
print err
|
||||
print e
|
||||
pass
|
||||
c.close()
|
||||
|
||||
def main():
|
||||
|
||||
|
||||
with con:
|
||||
cur = con.cursor()
|
||||
query = "SELECT * FROM tags WHERE deleted = 0;"
|
||||
cur.execute(query)
|
||||
tags = cur.fetchall()
|
||||
with con:
|
||||
cur = con.cursor()
|
||||
query = "SELECT * FROM tags WHERE deleted = 0;"
|
||||
cur.execute(query)
|
||||
tags = cur.fetchall()
|
||||
|
||||
configObj = {}
|
||||
configObj = {}
|
||||
|
||||
|
||||
with con:
|
||||
cur = con.cursor()
|
||||
query = "SELECT parameter, val FROM config GROUP BY parameter;"
|
||||
cur.execute(query)
|
||||
config = cur.fetchall()
|
||||
for x in config:
|
||||
configObj[x[0]] = x[1]
|
||||
with con:
|
||||
cur = con.cursor()
|
||||
query = "SELECT parameter, val FROM config GROUP BY parameter;"
|
||||
cur.execute(query)
|
||||
config = cur.fetchall()
|
||||
for x in config:
|
||||
configObj[x[0]] = x[1]
|
||||
|
||||
try:
|
||||
configProperties['PLC_IP_ADDRESS'] = str(configObj['ip_address'])
|
||||
print("FYI, using PLC IP Address from the database {0}".format(configProperties['PLC_IP_ADDRESS']))
|
||||
except KeyError:
|
||||
print("FYI, there is no PLC IP Address stored in the database, defaulting to 192.168.1.10")
|
||||
configProperties['PLC_IP_ADDRESS'] = "192.168.1.10"
|
||||
try:
|
||||
configProperties['PLC_IP_ADDRESS'] = str(configObj['ip_address'])
|
||||
print("FYI, using PLC IP Address from the database {0}".format(configProperties['PLC_IP_ADDRESS']))
|
||||
except KeyError:
|
||||
print("FYI, there is no PLC IP Address stored in the database, defaulting to 192.168.1.10")
|
||||
configProperties['PLC_IP_ADDRESS'] = "192.168.1.10"
|
||||
|
||||
try:
|
||||
configProperties['plc_type'] = str(configObj['plc_type'])
|
||||
print("FYI, using PLC Type from the database {0}".format(configProperties['plc_type']))
|
||||
except KeyError:
|
||||
print("FYI, there is no PLC Type stored in the database, defaulting to CLX")
|
||||
configProperties['plc_type'] = "CLX"
|
||||
try:
|
||||
configProperties['plc_type'] = str(configObj['plc_type'])
|
||||
print("FYI, using PLC Type from the database {0}".format(configProperties['plc_type']))
|
||||
except KeyError:
|
||||
print("FYI, there is no PLC Type stored in the database, defaulting to CLX")
|
||||
configProperties['plc_type'] = "CLX"
|
||||
|
||||
try:
|
||||
configProperties['scan_rate'] = int(configObj['scan_rate'])
|
||||
print("FYI, using Scan Rate from the database {0}".format(configProperties['scan_rate']))
|
||||
except KeyError:
|
||||
print("FYI, there is no Scan Rate stored in the database, defaulting to 10 seconds")
|
||||
configProperties['scan_rate'] = 10
|
||||
try:
|
||||
configProperties['scan_rate'] = int(configObj['scan_rate'])
|
||||
print("FYI, using Scan Rate from the database {0}".format(configProperties['scan_rate']))
|
||||
except KeyError:
|
||||
print("FYI, there is no Scan Rate stored in the database, defaulting to 10 seconds")
|
||||
configProperties['scan_rate'] = 10
|
||||
|
||||
try:
|
||||
sa_test = str(configObj['save_all'])
|
||||
if sa_test == "true":
|
||||
configProperties['save_all'] = True
|
||||
else:
|
||||
configProperties['save_all'] = False
|
||||
print("FYI, value for save_all is {0}".format(configProperties['save_all']))
|
||||
except KeyError:
|
||||
print("FYI, there is no save_all value stored in the database, using False")
|
||||
configProperties['save_all'] = False
|
||||
try:
|
||||
sa_test = str(configObj['save_all'])
|
||||
if sa_test == "true":
|
||||
configProperties['save_all'] = True
|
||||
else:
|
||||
configProperties['save_all'] = False
|
||||
print("FYI, value for save_all is {0}".format(configProperties['save_all']))
|
||||
except KeyError:
|
||||
print("FYI, there is no save_all value stored in the database, using False")
|
||||
configProperties['save_all'] = False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
tagList = []
|
||||
print("\nScan List\n--------------")
|
||||
if len(tags) > 0:
|
||||
for t in tags:
|
||||
tagList.append({"id": int(t[0]), "name": t[1], "val": None, "lastVal": None})
|
||||
print(t[1])
|
||||
print("--------------\n")
|
||||
tag_store = {}
|
||||
|
||||
while True:
|
||||
try:
|
||||
for r in tagList:
|
||||
r['val'] = 0
|
||||
if configProperties['plc_type'] == "u800":
|
||||
r["val"] = u800.readMicroTag(configProperties['PLC_IP_ADDRESS'], str(r['name']))[0]
|
||||
else:
|
||||
r["val"] = readTag(configProperties['PLC_IP_ADDRESS'], str(r['name']))[0]
|
||||
if len(tags) > 0:
|
||||
for t in tags:
|
||||
# (1, u'Pump Intake Pressure', u'5', u'Pump_Intake_Pressure', u'Pressure at the Intake of the Pump', None, 100.0, 3600, u'PSI', 0.0, 3000.0, u'2016-04-13 21:27:01', 0)
|
||||
tag_store[t[1]] = Tag(t[1], t[3], t[0], t[5], t[6], t[7], mapFn=t[8], plc_type=configProperties['plc_type'], plc_ip_address=configProperties['PLC_IP_ADDRESS'])
|
||||
|
||||
print("{0} - {1}".format(r["name"], r["val"]))
|
||||
if (not configProperties['save_all'] and not r["val"] == r["lastVal"]) or configProperties['save_all']:
|
||||
with con:
|
||||
cur = con.cursor()
|
||||
aQuery = """INSERT INTO vals (tagID, val) VALUES ('%d', '%f');""" % (r["id"], float(r["val"]))
|
||||
# print(aQuery)
|
||||
cur.execute(aQuery)
|
||||
con.commit()
|
||||
print("<saved>")
|
||||
r["lastVal"] = r["val"]
|
||||
print("-----------")
|
||||
time.sleep(configProperties['scan_rate'])
|
||||
|
||||
except Exception as err:
|
||||
print err
|
||||
main()
|
||||
while True:
|
||||
for tag in tag_store:
|
||||
try:
|
||||
tag_store[tag].read(configProperties['save_all'])
|
||||
except:
|
||||
print("ERROR EVALUATING {}".format(tag))
|
||||
traceback.print_exc()
|
||||
time.sleep(configProperties['scan_rate'])
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main()
|
||||
|
||||
276
python/tuxeip.py
276
python/tuxeip.py
@@ -1,276 +0,0 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# Copyright (C) 2014 Gayner Technical Services Pty Ltd
|
||||
|
||||
from ctypes import *
|
||||
|
||||
# PLC TYPES
|
||||
Unknow=0
|
||||
PLC=1
|
||||
SLC500=2
|
||||
LGX=3
|
||||
|
||||
# EIP DATA TYPES
|
||||
PLC_BIT=1
|
||||
PLC_BIT_STRING=2
|
||||
PLC_BYTE_STRING=3
|
||||
PLC_INTEGER=4
|
||||
PLC_TIMER=5
|
||||
PLC_COUNTER=6
|
||||
PLC_CONTROL=7
|
||||
PLC_FLOATING=8
|
||||
PLC_ARRAY=9
|
||||
PLC_ADRESS=15
|
||||
PLC_BCD=16
|
||||
|
||||
# LOGIX DATA TYPES
|
||||
LGX_BOOL=0xC1
|
||||
LGX_BITARRAY=0xD3
|
||||
LGX_SINT=0xC2
|
||||
LGX_INT=0xC3
|
||||
LGX_DINT=0xC4
|
||||
LGX_REAL=0xCA
|
||||
|
||||
class Eip_Session(Structure):
|
||||
_fields_ = [
|
||||
('sock',c_int),
|
||||
('Session_Handle', c_uint),
|
||||
('Sender_ContextL',c_int),
|
||||
('Sender_ContextH',c_int),
|
||||
('timeout', c_int),
|
||||
('references', c_int),
|
||||
('Data', c_void_p),
|
||||
]
|
||||
|
||||
class Eip_Connection(Structure):
|
||||
_fields_ = [
|
||||
('Eip_Session', Eip_Session),
|
||||
('references', c_int),
|
||||
('Data', c_void_p),
|
||||
('ConnectionSerialNumber', c_uint),
|
||||
('OriginatorVendorID', c_uint),
|
||||
('OriginatorSerialNumber', c_int),
|
||||
('OT_ConnID', c_int),
|
||||
('TO_ConnID', c_int),
|
||||
('packet', c_short),
|
||||
('Path_size', c_byte)
|
||||
]
|
||||
|
||||
class Eip_PLC_Read(Structure):
|
||||
_fields_ = [
|
||||
('type', c_int),
|
||||
('Varcount', c_int),
|
||||
('totalise', c_int),
|
||||
('elementsize', c_int),
|
||||
('mask', c_uint),
|
||||
]
|
||||
|
||||
class TuxEIPException(Exception):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.value)
|
||||
|
||||
class TuxEIP:
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.__libpath = kwargs.get("libpath", "libtuxeip.dylib")
|
||||
self.__tuxeip = CDLL(self.__libpath)
|
||||
self.__tuxeip._cip_err_msg.restype = c_char_p
|
||||
|
||||
def __del__(self):
|
||||
del self.__tuxeip
|
||||
|
||||
def OpenSession(self, slaveip_, slaveport_=44818, slavetimeout_=1000):
|
||||
self.__tuxeip._OpenSession.restype = POINTER(Eip_Session)
|
||||
|
||||
# Convert params to C types
|
||||
slaveip = c_char_p(slaveip_)
|
||||
slaveport = c_int(slaveport_)
|
||||
slavetimeout = c_int(slavetimeout_)
|
||||
|
||||
session = self.__tuxeip._OpenSession(slaveip, slaveport, slavetimeout)
|
||||
|
||||
#print self.__tuxeip._cip_err_msg, self.__tuxeip._cip_errno, self.__tuxeip._cip_ext_errno
|
||||
|
||||
if bool(session) == False:
|
||||
raise TuxEIPException("Could not open session to " + str(slaveip) + ":" + str(slaveport))
|
||||
|
||||
return session
|
||||
|
||||
def RegisterSession(self, sess_):
|
||||
self.__tuxeip._RegisterSession.restype = c_int
|
||||
reg = self.__tuxeip._RegisterSession(sess_)
|
||||
|
||||
if reg != False:
|
||||
raise TuxEIPException("Could not register session")
|
||||
|
||||
return reg
|
||||
|
||||
def ConnectPLCOverCNET(self, sess_, plctype_, priority_, timeoutticks_, connid_, conserial_,
|
||||
vendorid_, serialnum_, timeoutmult_, rpi_, transport_, slavepath_):
|
||||
# Convert params to C types
|
||||
priority = c_byte(priority_)
|
||||
timeoutticks = c_byte(timeoutticks_)
|
||||
connid = c_uint(connid_)
|
||||
conserial = c_ushort(conserial_)
|
||||
vendorid = c_ushort(vendorid_)
|
||||
serialnum = c_uint(serialnum_)
|
||||
timeutmult = c_byte(timeoutmult_)
|
||||
rpi = c_uint(rpi_)
|
||||
transport = c_byte(transport_)
|
||||
slavepath = c_char_p(slavepath_)
|
||||
pathlength = len(slavepath_)
|
||||
|
||||
self.__tuxeip._ConnectPLCOverCNET.restype = POINTER(Eip_Connection)
|
||||
|
||||
connection = self.__tuxeip._ConnectPLCOverCNET(
|
||||
sess_,
|
||||
plctype_,
|
||||
priority,
|
||||
timeoutticks,
|
||||
connid,
|
||||
conserial,
|
||||
vendorid,
|
||||
serialnum,
|
||||
timeutmult,
|
||||
rpi,
|
||||
transport,
|
||||
slavepath,
|
||||
pathlength
|
||||
)
|
||||
|
||||
if bool(connection) == False:
|
||||
raise TuxEIPException("Could not connect to CPU")
|
||||
|
||||
return connection
|
||||
|
||||
def ReadLgxData(self, sess_, conn_, var_, num_):
|
||||
self.__tuxeip._ReadLgxData.restype = POINTER(Eip_PLC_Read)
|
||||
readdata = self.__tuxeip._ReadLgxData(sess_, conn_, var_, num_)
|
||||
|
||||
if bool(readdata) == False:
|
||||
raise TuxEIPException("Read data failed")
|
||||
|
||||
return readdata
|
||||
|
||||
def WriteLGXData(self, sess_, conn_, address_, datatype_, data_, num_ ):
|
||||
if datatype_ == LGX_INT or datatype_ == LGX_BOOL or datatype_ == LGX_DINT or datatype_ == LGX_SINT:
|
||||
data = c_int(data_)
|
||||
elif datatype_ == LGX_REAL:
|
||||
data = c_float(data_)
|
||||
else:
|
||||
raise TuxEIPException("Write data failed")
|
||||
|
||||
data = self.__tuxeip._WriteLgxData(sess_, conn_, address_, datatype_, byref(data), num_)
|
||||
|
||||
return data
|
||||
|
||||
def ReadLGXDataAsFloat(self, sess_, conn_, var_, num_):
|
||||
data = self.ReadLgxData(sess_, conn_, var_, num_)
|
||||
d = self.GetLGXValueAsFloat(data)
|
||||
self.FreePLCRead(data)
|
||||
return d
|
||||
|
||||
def ReadLGXDataAsInteger(self, sess_, conn_, var_, num_):
|
||||
data = self.ReadLgxData(sess_, conn_, var_, num_)
|
||||
d = self.GetLGXValueAsInteger(data)
|
||||
self.FreePLCRead(data)
|
||||
return d
|
||||
|
||||
def ReadPLCDataAsFloat(self, sess_, conn_, dhp_, routepath_, routesize_, plctype_, tns_, address_, number_):
|
||||
data = self.ReadPLCData(sess_, conn_, dhp_, routepath_, routesize_, plctype_, tns_, address_, number_)
|
||||
d = self.PCCC_GetValueAsFloat(data)
|
||||
self.FreePLCRead(data)
|
||||
return d
|
||||
|
||||
def ReadPLCDataAsInteger(self, sess_, conn_, dhp_, routepath_, routesize_, plctype_, tns_, address_, number_):
|
||||
data = self.ReadPLCData(sess_, conn_, dhp_, routepath_, routesize_, plctype_, tns_, address_, number_)
|
||||
d = self.PCCC_GetValueAsInteger(data)
|
||||
self.FreePLCRead(data)
|
||||
return d
|
||||
|
||||
def ReadPLCData(self, sess_, conn_, dhp_, routepath_, routesize_, plctype_, tns_, address_, number_):
|
||||
self.__tuxeip._ReadPLCData.restype = POINTER(Eip_PLC_Read)
|
||||
readdata = self.__tuxeip._ReadPLCData(sess_, conn_, dhp_, routepath_, routesize_, plctype_,
|
||||
tns_, address_, number_)
|
||||
|
||||
if bool(readdata) == False:
|
||||
raise TuxEIPException("Read data failed")
|
||||
|
||||
return readdata
|
||||
|
||||
def GetLGXValueAsFloat(self, readdata_):
|
||||
if bool(readdata_) == False:
|
||||
return None
|
||||
|
||||
self.__tuxeip._GetLGXValueAsFloat.restype = c_float
|
||||
values = []
|
||||
for i in range(0, readdata_.contents.Varcount):
|
||||
v = self.__tuxeip._GetLGXValueAsFloat(readdata_, i)
|
||||
values.append(v)
|
||||
|
||||
return values
|
||||
|
||||
def GetLGXValueAsInteger(self, readdata_):
|
||||
if bool(readdata_) == False:
|
||||
return None
|
||||
|
||||
self.__tuxeip._GetLGXValueAsInteger.restype = c_int
|
||||
values = []
|
||||
for i in range(0, readdata_.contents.Varcount):
|
||||
v = self.__tuxeip._GetLGXValueAsInteger(readdata_, i)
|
||||
values.append(v)
|
||||
|
||||
return values
|
||||
|
||||
def PCCC_GetValueAsFloat(self, readdata_):
|
||||
if bool(readdata_) == False:
|
||||
return None
|
||||
|
||||
self.__tuxeip._PCCC_GetValueAsFloat.restype = c_float
|
||||
values = []
|
||||
for i in range(0, readdata_.contents.Varcount):
|
||||
v = self.__tuxeip._PCCC_GetValueAsFloat(readdata_, i)
|
||||
values.append(v)
|
||||
|
||||
return values
|
||||
|
||||
def PCCC_GetValueAsInteger(self, readdata_):
|
||||
if bool(readdata_) == False:
|
||||
return None
|
||||
|
||||
self.__tuxeip._PCCC_GetValueAsInteger.restype = c_int
|
||||
values = []
|
||||
for i in range(0, readdata_.contents.Varcount):
|
||||
v = self.__tuxeip._PCCC_GetValueAsInteger(readdata_, i)
|
||||
values.append(v)
|
||||
|
||||
return values
|
||||
|
||||
def WritePLCData(self, sess_, conn_, dhp_, routepath_, routesize_, plctype_, tns_, address_, datatype_, data_, number_):
|
||||
|
||||
if datatype_ == PLC_INTEGER:
|
||||
data = c_int(data_)
|
||||
elif datatype_ == PLC_FLOATING:
|
||||
data = c_float(data_)
|
||||
else:
|
||||
raise TuxEIPException("Variable type not supported" + str(datatype_))
|
||||
|
||||
result = self.__tuxeip._WritePLCData(sess_, conn_, dhp_, routepath_, routesize_, plctype_,
|
||||
tns_, address_, datatype_, byref(data), number_)
|
||||
|
||||
return result
|
||||
|
||||
def Forward_Close(self, conn_):
|
||||
self.__tuxeip._Forward_Close(conn_)
|
||||
|
||||
def UnRegisterSession(self, sess_):
|
||||
self.__tuxeip._UnRegisterSession(sess_)
|
||||
|
||||
def CloseSession(self, sess_):
|
||||
self.__tuxeip.CloseSession(sess_)
|
||||
|
||||
def FreePLCRead(self, data_):
|
||||
self.__tuxeip._FreePLCRead(data_)
|
||||
Binary file not shown.
101
www/app.coffee
Normal file
101
www/app.coffee
Normal file
@@ -0,0 +1,101 @@
|
||||
express = require('express')
|
||||
path = require('path')
|
||||
fs = require('fs')
|
||||
logger = require('morgan')
|
||||
methodOverride = require('method-override')
|
||||
bodyParser = require('body-parser')
|
||||
errorHandler = require('errorhandler')
|
||||
app = express()
|
||||
fns = undefined
|
||||
|
||||
app.locals.DB_TYPE = 'MySQL'
|
||||
# or "MySQL"
|
||||
|
||||
###*
|
||||
* Configuration
|
||||
###
|
||||
|
||||
if app.locals.DB_TYPE == 'MySQL'
|
||||
fns = require('./functions_MySQL.coffee')
|
||||
mysql = require('mysql')
|
||||
db_config =
|
||||
host: 'localhost'
|
||||
user: 'website'
|
||||
password: 'henrypump'
|
||||
database: 'poconsole'
|
||||
app.locals.pool = mysql.createPool(db_config)
|
||||
|
||||
# handleDisconnect = ->
|
||||
# console.log 'Handling db disconnect gracefully'
|
||||
# app.locals.db = mysql.createConnection(db_config)
|
||||
# app.locals.db.connect (err) ->
|
||||
# if err
|
||||
# console.log 'error when connecting to db:', err
|
||||
# setTimeout handleDisconnect, 2000
|
||||
# return
|
||||
# app.locals.db.on 'error', (err) ->
|
||||
# console.log 'db error', err
|
||||
# if err.code == 'PROTOCOL_CONNECTION_LOST'
|
||||
# handleDisconnect()
|
||||
# else
|
||||
# throw err
|
||||
# return
|
||||
# return
|
||||
# handleDisconnect()
|
||||
else
|
||||
fns = require('./functions_SQLite.coffee')
|
||||
|
||||
app.set 'port', process.env.PORT or 80
|
||||
app.set 'views', path.join(__dirname, 'views')
|
||||
app.engine '.html', require('ejs').renderFile
|
||||
app.set 'view engine', 'html'
|
||||
#app.use(favicon(__dirname + '/public/img/favicon.ico'));
|
||||
app.use logger('dev')
|
||||
app.use methodOverride()
|
||||
app.use bodyParser.json()
|
||||
app.use bodyParser.urlencoded(extended: true)
|
||||
#app.use(express["static"](path.join(__dirname, 'public')));
|
||||
app.use express.static(__dirname + '/public')
|
||||
app.use '/bower_components', express.static(__dirname + '/bower_components')
|
||||
app.use '/node_modules', express.static(__dirname + '/node_modules')
|
||||
|
||||
###*
|
||||
* Routes
|
||||
###
|
||||
|
||||
angular = (req, res) ->
|
||||
res.render 'angularIndex'
|
||||
return
|
||||
|
||||
app.post '/json/tag/add', fns.createTag # Adds a tag to the scan list
|
||||
app.post '/json/tag/update/', fns.updateTag # Updates tag data
|
||||
app.get '/json/tag/delete/:tag', fns.deleteTag # Removes a tag from the scan list
|
||||
app.get '/json/tag/:id', fns.getTag # Gets a specific tag in the scan list
|
||||
app.get '/json/tag', fns.getAllTags # Lists all tags in the scan list
|
||||
app.get '/json/val/:tag', fns.latestValueSingleTag # Gets the latest value of a single tag
|
||||
app.get '/json/series/:tag/:hours', fns.seriesTagValues # Gets all the values of a tag for the last X hours
|
||||
app.get '/json/valBetween/:tag/:startDatetime/:endDatetime', fns.seriesTagValuesBetween # Gets the values of a tag between the start time and end time
|
||||
app.get '/json/CSV/all', fns.allDataCSV # Gets a CSV of all values stored
|
||||
app.get '/json/CSV/:tag/:startDatetime/:endDatetime', fns.seriesCSVBetween # Gets a CSV of the values of a tag between the start time and end time
|
||||
app.get '/json/CSV/:tag/:hours', fns.seriesCSV # Gets a CSV of the values of a tag for the last x hours
|
||||
app.get '/json/all', fns.latestValueAllTags # Gets the latest values of all tags in the scan list
|
||||
app.get '/json/config', fns.getSetup # Gets the contents of the config table
|
||||
app.post '/json/config', fns.updateSetup # Adds a new parameter to the config table
|
||||
app.get '/json/logger/status', fns.checkLoggerStatus # Gets the status of the data logger
|
||||
app.get '/json/logger/restart', fns.restartLogger # Restarts the data logger
|
||||
app.get '/json/clearDatabase/all', fns.clearValues # Removes all tag values from the database
|
||||
app.get '/json/clearDatabase/:id', fns.clearValues # Removes tag values from the database
|
||||
app.get '*', angular
|
||||
|
||||
###*
|
||||
* Start Server
|
||||
###
|
||||
|
||||
connectionsArray = []
|
||||
s_port = 3000
|
||||
server = app.listen(s_port, ->
|
||||
host = server.address().address
|
||||
port = server.address().port
|
||||
console.log 'POConsole listening at http://%s:%s', host, port
|
||||
return
|
||||
)
|
||||
@@ -1,18 +1,51 @@
|
||||
CREATE DATABASE TagData;
|
||||
CREATE TABLE `TagData`.`tags` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`tagName` VARCHAR(128) NULL,
|
||||
`dateAdded` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`units` VARCHAR(16) NULL,
|
||||
`deleted` INT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`));
|
||||
CREATE DATABASE poconsole;
|
||||
USE poconsole;
|
||||
CREATE TABLE IF NOT EXISTS tag_classes(
|
||||
id int(11) NOT NULL AUTO_INCREMENT,
|
||||
tag_class varchar(64),
|
||||
description varchar(64),
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE `TagData`.`values` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`tagID` INT NULL,
|
||||
`val` FLOAT NULL,
|
||||
`dateAdded` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`));
|
||||
CREATE TABLE IF NOT EXISTS tags(
|
||||
id int(11) NOT NULL AUTO_INCREMENT,
|
||||
name varchar(128),
|
||||
class int(11),
|
||||
tag varchar(128),
|
||||
description varchar(128),
|
||||
data_type varchar(32),
|
||||
change_threshold float,
|
||||
guarantee_sec integer(11),
|
||||
map_function varchar(64),
|
||||
units varchar(64),
|
||||
minExpected varchar(64),
|
||||
maxExpected varchar(64),
|
||||
deleted INT NULL DEFAULT 0,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tag_vals(
|
||||
id int(11) NOT NULL AUTO_INCREMENT,
|
||||
dtime datetime,
|
||||
tagID int,
|
||||
val float,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS config (
|
||||
id INT NOT NULL AUTO_INCREMENT,
|
||||
parameter varchar(128),
|
||||
val varchar(128),
|
||||
dateAdded TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
INSERT INTO poconsole.tag_classes (id, tag_class, description) VALUES (1, 'stroke', 'Stroke Information');
|
||||
INSERT INTO poconsole.tag_classes (id, tag_class, description) VALUES (2, 'history', 'Historical Data');
|
||||
INSERT INTO poconsole.tag_classes (id, tag_class, description) VALUES (3, 'gaugeoff', 'Gauge Off Data');
|
||||
INSERT INTO poconsole.tag_classes (id, tag_class, description) VALUES (4, 'welltest', 'Well Test Data');
|
||||
INSERT INTO poconsole.tag_classes (id, tag_class, description) VALUES (5, 'custom', 'Custom tags');
|
||||
|
||||
CREATE USER 'website'@'localhost' IDENTIFIED BY 'henrypump';
|
||||
GRANT ALL ON *.* TO 'website'@'localhost';
|
||||
@@ -20,4 +53,4 @@ CREATE USER 'admin'@'localhost' IDENTIFIED BY 'henrypump';
|
||||
GRANT ALL ON *.* to 'admin'@'localhost';
|
||||
CREATE USER 'admin'@'%' IDENTIFIED BY 'henrypump';
|
||||
GRANT ALL ON *.* to 'admin'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
CREATE TABLE IF NOT EXISTS tag_classes(
|
||||
id INTEGER PRIMARY KEY,
|
||||
tag_class TEXT,
|
||||
description TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tags (
|
||||
id INTEGER PRIMARY KEY,
|
||||
tagName TEXT,
|
||||
vanityName TEXT,
|
||||
name TEXT,
|
||||
class TEXT,
|
||||
tag TEXT,
|
||||
description TEXT,
|
||||
data_type TEXT,
|
||||
change_threshold REAL,
|
||||
guarantee_sec INTEGER,
|
||||
units TEXT,
|
||||
minExpected REAL,
|
||||
maxExpected REAL,
|
||||
@@ -10,11 +20,11 @@ CREATE TABLE IF NOT EXISTS tags (
|
||||
deleted INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS vals (
|
||||
CREATE TABLE IF NOT EXISTS tag_vals (
|
||||
id INTEGER PRIMARY KEY,
|
||||
tagID INTEGER,
|
||||
val REAL,
|
||||
dateAdded TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
dtime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS config (
|
||||
@@ -23,3 +33,9 @@ CREATE TABLE IF NOT EXISTS config (
|
||||
val TEXT,
|
||||
dateAdded TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT INTO tag_classes (id, tag_class, description) VALUES (1, 'stroke', 'Stroke Information');
|
||||
INSERT INTO tag_classes (id, tag_class, description) VALUES (2, 'history', 'Historical Data');
|
||||
INSERT INTO tag_classes (id, tag_class, description) VALUES (3, 'gaugeoff', 'Gauge Off Data');
|
||||
INSERT INTO tag_classes (id, tag_class, description) VALUES (4, 'welltest', 'Well Test Data');
|
||||
INSERT INTO tag_classes (id, tag_class, description) VALUES (5, 'custom', 'Custom tags');
|
||||
|
||||
418
www/functions_MySQL.coffee
Normal file
418
www/functions_MySQL.coffee
Normal file
@@ -0,0 +1,418 @@
|
||||
# var dbFile = "/usr/db/data.db";
|
||||
dbFile = '/mnt/usb/data.db'
|
||||
# var dbFile = '/Users/patrickjmcd/data.db';
|
||||
|
||||
|
||||
dString_to_sqlite = (dString) ->
|
||||
###*
|
||||
* Takes a date string in the form YYYYMMDD_HHmmSS and returns it in SQLite format (YYYY-MM-DD HH:mm:SS)
|
||||
* @param {String} dString
|
||||
* @return {String} sqliteString
|
||||
###
|
||||
|
||||
re = /(\d{4})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2})/
|
||||
fd = re.exec(dString)
|
||||
if fd
|
||||
sqliteString = ''
|
||||
sqliteString.concat fd[1], '-', fd[2], '-', fd[3], ' ', fd[4], ':', fd[5], ':', fd[6]
|
||||
else
|
||||
null
|
||||
|
||||
|
||||
sqlite_to_dString = (sqliteDate) ->
|
||||
###*
|
||||
* Takes a sqlite date string in the form YYYY-MM-DD HH:mm:SS and returns it in format YYYYMMDD_HHmmSS
|
||||
* @param {String} sqliteDate
|
||||
* @return {String} dString
|
||||
###
|
||||
|
||||
re = /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/
|
||||
fd = re.exec(sqliteDate)
|
||||
if fd
|
||||
dString = ''
|
||||
dString.concat fd[1], fd[2], fd[3], '_', fd[4], fd[5], fd[6]
|
||||
else
|
||||
null
|
||||
|
||||
|
||||
getAllTags = (pool, callback) ->
|
||||
pool.getConnection (err, db)->
|
||||
query = 'SELECT * FROM tags WHERE deleted = 0'
|
||||
db.query query, (err, rows, fields) ->
|
||||
db.release()
|
||||
if err
|
||||
return callback(err, null)
|
||||
console.log err
|
||||
else
|
||||
return callback(null, rows)
|
||||
undefined
|
||||
|
||||
|
||||
exports.getAllTags = (req, res) ->
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'SELECT * FROM tags WHERE deleted = 0'
|
||||
db.query query, (err, rows, fields) ->
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
tags: rows
|
||||
undefined
|
||||
|
||||
|
||||
exports.createTag = (req, res) ->
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'INSERT INTO tags (tag, units, minExpected, maxExpected, name, description, class, guarantee_sec, change_threshold) VALUES (?, ?, ?, ?, ?, ?, 5, ?, ?)'
|
||||
db.query query, [req.body.tag, req.body.units, req.body.minExpected, req.body.maxExpected, req.body.name, req.body.description, req.body.guarantee_sec, req.body.change_threshold], (err, results) ->
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json status: 'OK'
|
||||
undefined
|
||||
|
||||
|
||||
exports.getTag = (req, res) ->
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'SELECT * FROM tags WHERE id = ?'
|
||||
db.query query, [req.params.id], (err, rows) ->
|
||||
db.release()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
tags: rows
|
||||
undefined
|
||||
|
||||
|
||||
exports.updateTag = (req, res) ->
|
||||
console.log(req.body)
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'UPDATE tags set tag = ?, units = ?, minExpected = ?, maxExpected = ?, name = ?, description = ?, guarantee_sec = ?, change_threshold = ? WHERE id = ?'
|
||||
db.query query, [req.body.tag, req.body.units, req.body.minExpected, req.body.maxExpected, req.body.name, req.body.description, req.body.guarantee_sec, req.body.change_threshold, req.body.id], (err, results) ->
|
||||
db.release()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
undefined
|
||||
|
||||
exports.deleteTag = (req, res) ->
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'UPDATE tags SET deleted = 1 WHERE id = ?'
|
||||
db.query query, [req.params.tag], (err, results) ->
|
||||
db.release()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
undefined
|
||||
|
||||
exports.seriesTagValues = (req, res) ->
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'SELECT * FROM tag_vals WHERE tagID = ? AND dateAdded >= DATE_SUB(NOW(), INTERVAL 1 HOUR)'
|
||||
db.query query, [parseInt(req.params.tag)], (err, rows) ->
|
||||
db.release()
|
||||
if err
|
||||
console.log err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
query: query
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
tag: req.params.tag
|
||||
vals: rows
|
||||
undefined
|
||||
|
||||
exports.seriesTagValuesBetween = (req, res) ->
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'SELECT * FROM tag_vals WHERE tagID = ? AND dtime >= ? AND dtime <= ?'
|
||||
db.query query, [parseInt(req.params.tag), dString_to_sqlite(req.params.startDatetime), dString_to_sqlite(req.params.endDatetime)], (err, rows) ->
|
||||
db.release()
|
||||
if err
|
||||
console.log err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
query: query
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
tag: req.params.tag
|
||||
startDatetime: dString_to_sqlite(req.params.startDatetime)
|
||||
endDatetime: dString_to_sqlite(req.params.endDatetime)
|
||||
vals: rows
|
||||
undefined
|
||||
|
||||
createCSVrow = (header, dataRow) ->
|
||||
i = header.indexOf(dataRow.name)
|
||||
csvRow = dataRow.id.toString() + ',' + dataRow.dtime + ','
|
||||
if i >= 0
|
||||
j = 2
|
||||
while j < header.length
|
||||
if j == i
|
||||
csvRow = csvRow + dataRow.val.toString() + ','
|
||||
else
|
||||
csvRow = csvRow + ','
|
||||
j++
|
||||
csvRow = csvRow.slice(0, -1) + '\u000d'
|
||||
return csvRow
|
||||
return
|
||||
|
||||
exports.allDataCSV = (req, res) ->
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'SELECT v.id, t.name, v.val, v.dtime FROM tags t JOIN tag_vals v ON t.id = v.tagID'
|
||||
db.query query, (err, rows) ->
|
||||
db.release()
|
||||
if err
|
||||
console.log err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
query: query
|
||||
else
|
||||
getAllTags req.app.locals.pool, (err, tags) ->
|
||||
if err
|
||||
console.log err
|
||||
else
|
||||
csvString = ''
|
||||
da = [
|
||||
'id'
|
||||
'DateAdded'
|
||||
]
|
||||
tagVanityNames = tags.map((t) ->
|
||||
t.name
|
||||
)
|
||||
h = da.concat(tagVanityNames)
|
||||
console.log h
|
||||
csvString = csvString + h.join(',') + '\u000d'
|
||||
i = 0
|
||||
while i < rows.length
|
||||
csvString = csvString + createCSVrow(h, rows[i])
|
||||
i++
|
||||
res.set 'Content-Type', 'text/csv'
|
||||
res.set 'Content-Disposition', 'attachment;filename=tagdata.csv'
|
||||
res.send csvString
|
||||
undefined
|
||||
|
||||
exports.seriesCSV = (req, res) ->
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'SELECT v.id, t.name, v.val, v.dateAdded FROM tags t JOIN tag_vals v ON t.id = v.tagID WHERE tagID = ? AND v.dateAdded > DATETIME(\'now\', \'-1 HOUR\')'
|
||||
db.query query, [parseInt(req.params.tag)], (err, rows) ->
|
||||
db.release()
|
||||
if err
|
||||
console.log err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
query: query
|
||||
else
|
||||
csvString = ''
|
||||
h = [
|
||||
'id'
|
||||
'DateAdded'
|
||||
rows[0].vanityName
|
||||
]
|
||||
csvString = csvString + h.join(',') + '\u000d'
|
||||
i = 0
|
||||
while i < rows.length
|
||||
csvString = csvString + [
|
||||
rows[i].id
|
||||
rows[i].dateAdded
|
||||
rows[i].val
|
||||
].join(',') + '\u000d'
|
||||
i++
|
||||
res.set 'Content-Type', 'text/csv'
|
||||
res.set 'Content-Disposition', 'attachment;filename=tagdata.csv'
|
||||
res.send csvString
|
||||
undefined
|
||||
|
||||
exports.seriesCSVBetween = (req, res) ->
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'SELECT v.id, t.name, v.val, v.dtime FROM tags t JOIN tag_vals v ON t.id = v.tagID WHERE tagID = ? AND v.dtime >= ? AND v.dtime <= ?'
|
||||
db.query query, [parseInt(req.params.tag), dString_to_sqlite(req.params.startDatetime), dString_to_sqlite(req.params.endDatetime)], (err, rows) ->
|
||||
db.release()
|
||||
if err
|
||||
console.log err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
query: query
|
||||
else
|
||||
csvString = ''
|
||||
h = [
|
||||
'id'
|
||||
'DateAdded'
|
||||
rows[0].name
|
||||
]
|
||||
csvString = csvString + h.join(',') + '\u000d'
|
||||
i = 0
|
||||
while i < rows.length
|
||||
csvString = csvString + [
|
||||
rows[i].id
|
||||
rows[i].dtime
|
||||
rows[i].val
|
||||
].join(',') + '\u000d'
|
||||
i++
|
||||
res.set 'Content-Type', 'text/csv'
|
||||
res.set 'Content-Disposition', 'attachment;filename=tagdata.csv'
|
||||
res.send csvString
|
||||
undefined
|
||||
|
||||
exports.latestValueSingleTag = (req, res) ->
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'SELECT * FROM tag_vals WHERE id = (SELECT MAX(id) FROM tag_vals WHERE tagID = ?)'
|
||||
db.query query, [req.params.tag], (err, rows) ->
|
||||
db.release()
|
||||
console.log rows
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
tag_val: rows[0]
|
||||
undefined
|
||||
|
||||
exports.latestValueAllTags = (req, res) ->
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'SELECT v1.id as id, v1.dtime as dtime, t.id as t_id, t.name as name, t.tag as tag, v1.val as val, t.units as units, t.description as description, t.minExpected as minExpected, t.maxExpected as maxExpected FROM tag_vals v1 LEFT JOIN tags t ON t.id = v1.tagID WHERE v1.id = (SELECT v2.id FROM tag_vals v2 WHERE v2.tagID = v1.tagID ORDER BY v2.id DESC LIMIT 1)'
|
||||
db.query query, [req.params.id], (err, rows) ->
|
||||
db.release()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
vals: rows
|
||||
undefined
|
||||
|
||||
exports.checkLoggerStatus = (req, res) ->
|
||||
fs = require('fs')
|
||||
# var ps = require("ps-node");
|
||||
running = require('is-running')
|
||||
fs.readFile '/root/tagserver.pid', (derr, ddata) ->
|
||||
if derr
|
||||
console.log 'Problem getting PID of tagserver'
|
||||
res.json
|
||||
status: 'error'
|
||||
message: 'Problem getting PID of tagserver'
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
running: running(ddata)
|
||||
return
|
||||
return
|
||||
|
||||
exports.restartLogger = (req, res) ->
|
||||
exec = require('child_process').exec
|
||||
exec '/etc/init.d/loggers start', (error, stdout, stderr) ->
|
||||
if error
|
||||
res.json
|
||||
status: 'error'
|
||||
message: error
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
return
|
||||
return
|
||||
|
||||
exports.getSetup = (req, res) ->
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'SELECT parameter, val, dateAdded FROM config GROUP BY parameter;'
|
||||
db.query query, [req.params.id], (err, rows) ->
|
||||
db.release()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
config: rows
|
||||
undefined
|
||||
|
||||
exports.updateSetup = (req, res) ->
|
||||
exec = require('child_process').exec
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'INSERT INTO config (parameter, val) VALUES (?, ?)';
|
||||
db.query query, [req.body.parameter, req.body.val], (err) ->
|
||||
db.release()
|
||||
if err
|
||||
console.log runErr: err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
query: query
|
||||
else
|
||||
res.redirect '/#/setup'
|
||||
exec '/etc/init.d/loggers stop', (error, stdout, stderr) ->
|
||||
if error
|
||||
console.log
|
||||
status: 'error'
|
||||
message: error
|
||||
query: query
|
||||
setTimeout (->
|
||||
exec '/etc/init.d/loggers start', (error, stdout, stderr) ->
|
||||
if error
|
||||
console.log
|
||||
status: 'error'
|
||||
message: error
|
||||
query: query
|
||||
), 5000
|
||||
undefined
|
||||
|
||||
exports.clearValues = (req, res) ->
|
||||
if req.params.id
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'DELETE FROM tag_vals WHERE tagID = ?;';
|
||||
db.query query, [req.params.id], (err) ->
|
||||
db.release()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
else
|
||||
req.app.locals.pool.getConnection (err, db) ->
|
||||
query = 'DELETE FROM tag_vals WHERE id >= 0;';
|
||||
db.query query, (err) ->
|
||||
db.release()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
undefined
|
||||
@@ -76,5 +76,5 @@ exports.allTags = function(req, res){
|
||||
};
|
||||
|
||||
exports.allValues = function(req, res){
|
||||
res.json(status:"error", message:"not implemented"});
|
||||
res.json({status:"error", message:"not implemented"});
|
||||
};
|
||||
|
||||
517
www/functions_SQLite.coffee
Normal file
517
www/functions_SQLite.coffee
Normal file
@@ -0,0 +1,517 @@
|
||||
# var dbFile = "/usr/db/data.db";
|
||||
dbFile = '/mnt/usb/data.db'
|
||||
# var dbFile = '/Users/patrickjmcd/data.db';
|
||||
|
||||
|
||||
dString_to_sqlite = (dString) ->
|
||||
###*
|
||||
* Takes a date string in the form YYYYMMDD_HHmmSS and returns it in SQLite format (YYYY-MM-DD HH:mm:SS)
|
||||
* @param {String} dString
|
||||
* @return {String} sqliteString
|
||||
###
|
||||
|
||||
re = /(\d{4})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2})/
|
||||
fd = re.exec(dString)
|
||||
if fd
|
||||
sqliteString = ''
|
||||
sqliteString.concat fd[1], '-', fd[2], '-', fd[3], ' ', fd[4], ':', fd[5], ':', fd[6]
|
||||
else
|
||||
null
|
||||
|
||||
|
||||
sqlite_to_dString = (sqliteDate) ->
|
||||
###*
|
||||
* Takes a sqlite date string in the form YYYY-MM-DD HH:mm:SS and returns it in format YYYYMMDD_HHmmSS
|
||||
* @param {String} sqliteDate
|
||||
* @return {String} dString
|
||||
###
|
||||
|
||||
re = /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/
|
||||
fd = re.exec(sqliteDate)
|
||||
if fd
|
||||
dString = ''
|
||||
dString.concat fd[1], fd[2], fd[3], '_', fd[4], fd[5], fd[6]
|
||||
else
|
||||
null
|
||||
|
||||
|
||||
getAllTags = (callback) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'SELECT * FROM tags WHERE deleted = 0'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.all (err, rows) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
return callback(err, null)
|
||||
console.log err
|
||||
else
|
||||
return callback(null, rows)
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
exports.getAllTags = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'SELECT * FROM tags WHERE deleted = 0'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.all (err, rows) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
tags: rows
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
exports.createTag = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'INSERT INTO tags (tag, units, minExpected, maxExpected, name, description, class, guarantee_sec, change_threshold) VALUES (?, ?, ?, ?, ?, ?, 5, ?, ?)'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.run req.body.tag, req.body.units, req.body.minExpected, req.body.maxExpected, req.body.name, req.body.description, req.body.guarantee_sec, req.body.change_threshold, (err) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json status: 'OK'
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
exports.getTag = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'SELECT * FROM tags WHERE id = ?'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.all req.params.id, (err, rows) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
tags: rows
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
exports.updateTag = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'UPDATE tags set tag = ?, units = ?, minExpected = ?, maxExpected = ?, name = ?, description = ?, guarantee_sec = ?, change_threshold = ? WHERE id = ?'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.run req.body.tag, req.body.units, req.body.minExpected, req.body.maxExpected, req.body.name, req.body.description, req.body.guarantee_sec, req.body.change_threshold, req.body.id, (err) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
exports.deleteTag = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'UPDATE tags SET deleted = 1 WHERE id = ?'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.run req.params.tag, (err) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
exports.seriesTagValues = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'SELECT * FROM tag_vals WHERE tagID = ? AND dtime > DATETIME(\'now\', \'-1 HOUR\')'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.all parseInt(req.params.tag), (err, rows) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
console.log err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
query: query
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
tag: req.params.tag
|
||||
vals: rows
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
exports.seriesTagValuesBetween = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'SELECT * FROM tag_vals WHERE tagID = ? AND dtime >= DATETIME(?) AND dtime <= DATETIME(?)'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.all parseInt(req.params.tag), dString_to_sqlite(req.params.startDatetime), dString_to_sqlite(req.params.endDatetime), (err, rows) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
console.log err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
query: query
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
tag: req.params.tag
|
||||
startDatetime: dString_to_sqlite(req.params.startDatetime)
|
||||
endDatetime: dString_to_sqlite(req.params.endDatetime)
|
||||
vals: rows
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
createCSVrow = (header, dataRow) ->
|
||||
i = header.indexOf(dataRow.name)
|
||||
csvRow = dataRow.id.toString() + ',' + dataRow.dtime + ','
|
||||
if i >= 0
|
||||
j = 2
|
||||
while j < header.length
|
||||
if j == i
|
||||
csvRow = csvRow + dataRow.val.toString() + ','
|
||||
else
|
||||
csvRow = csvRow + ','
|
||||
j++
|
||||
csvRow = csvRow.slice(0, -1) + '\u000d'
|
||||
return csvRow
|
||||
return
|
||||
|
||||
exports.allDataCSV = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'SELECT v.id, t.name, v.val, v.dtime FROM tags t JOIN tag_vals v ON t.id = v.tagID'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.all (err, rows) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
console.log err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
query: query
|
||||
else
|
||||
getAllTags (err, tags) ->
|
||||
if err
|
||||
console.log err
|
||||
else
|
||||
csvString = ''
|
||||
da = [
|
||||
'id'
|
||||
'dtime'
|
||||
]
|
||||
tagnames = tags.map((t) ->
|
||||
t.name
|
||||
)
|
||||
h = da.concat(tagnames)
|
||||
console.log h
|
||||
csvString = csvString + h.join(',') + '\u000d'
|
||||
i = 0
|
||||
while i < rows.length
|
||||
csvString = csvString + createCSVrow(h, rows[i])
|
||||
i++
|
||||
res.set 'Content-Type', 'text/csv'
|
||||
res.set 'Content-Disposition', 'attachment;filename=tagdata.csv'
|
||||
res.send csvString
|
||||
return
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
exports.seriesCSV = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'SELECT v.id, t.name, v.val, v.dtime FROM tags t JOIN tag_vals v ON t.id = v.tagID WHERE tagID = ? AND v.dtime > DATETIME(\'now\', \'-1 HOUR\')'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.all parseInt(req.params.tag), (err, rows) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
console.log err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
query: query
|
||||
else
|
||||
csvString = ''
|
||||
h = [
|
||||
'id'
|
||||
'dtime'
|
||||
rows[0].name
|
||||
]
|
||||
csvString = csvString + h.join(',') + '\u000d'
|
||||
i = 0
|
||||
while i < rows.length
|
||||
csvString = csvString + [
|
||||
rows[i].id
|
||||
rows[i].dtime
|
||||
rows[i].val
|
||||
].join(',') + '\u000d'
|
||||
i++
|
||||
res.set 'Content-Type', 'text/csv'
|
||||
res.set 'Content-Disposition', 'attachment;filename=tagdata.csv'
|
||||
res.send csvString
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
exports.seriesCSVBetween = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'SELECT v.id, t.name, v.val, v.dtime FROM tags t JOIN tag_vals v ON t.id = v.tagID WHERE tagID = ? AND dtime >= DATETIME(?) AND dtime <= DATETIME(?)'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.all parseInt(req.params.tag), dString_to_sqlite(req.params.startDatetime), dString_to_sqlite(req.params.endDatetime), (err, rows) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
console.log err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
query: query
|
||||
else
|
||||
csvString = ''
|
||||
h = [
|
||||
'id'
|
||||
'dtime'
|
||||
rows[0].name
|
||||
]
|
||||
csvString = csvString + h.join(',') + '\u000d'
|
||||
i = 0
|
||||
while i < rows.length
|
||||
csvString = csvString + [
|
||||
rows[i].id
|
||||
rows[i].dtime
|
||||
rows[i].val
|
||||
].join(',') + '\u000d'
|
||||
i++
|
||||
res.set 'Content-Type', 'text/csv'
|
||||
res.set 'Content-Disposition', 'attachment;filename=tagdata.csv'
|
||||
res.send csvString
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
exports.latestValueSingleTag = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'SELECT * FROM tag_vals WHERE id = (SELECT MAX(id) FROM tag_vals WHERE tagID = ?)'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.all req.params.tag, (err, rows) ->
|
||||
console.log rows
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
tag_val: rows[0]
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
exports.latestValueAllTags = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
db.serialize ->
|
||||
query = 'SELECT t.tag as tag, t.name as name, t.description as description, t.units as units, t.id as t_id, t.minExpected as min, t.maxExpected as max, MAX(v.id) as v_id, v.val as val, v.dtime as dtime FROM tag_vals v JOIN tags t ON v.tagID = t.id WHERE t.deleted = 0 GROUP BY v.tagID'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.all req.params.id, (err, rows) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
vals: rows
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
exports.checkLoggerStatus = (req, res) ->
|
||||
fs = require('fs')
|
||||
# var ps = require("ps-node");
|
||||
running = require('is-running')
|
||||
fs.readFile '/root/tagserver.pid', (derr, ddata) ->
|
||||
if derr
|
||||
console.log 'Problem getting PID of tagserver'
|
||||
res.json
|
||||
status: 'error'
|
||||
message: 'Problem getting PID of tagserver'
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
running: running(ddata)
|
||||
return
|
||||
return
|
||||
|
||||
exports.restartLogger = (req, res) ->
|
||||
exec = require('child_process').exec
|
||||
exec '/etc/init.d/loggers start', (error, stdout, stderr) ->
|
||||
if error
|
||||
res.json
|
||||
status: 'error'
|
||||
message: error
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
return
|
||||
return
|
||||
|
||||
exports.getSetup = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
query = 'SELECT parameter, val, dateAdded FROM config GROUP BY parameter;'
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.all req.params.id, (err, rows) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
config: rows
|
||||
return
|
||||
return
|
||||
|
||||
exports.updateSetup = (req, res) ->
|
||||
exec = require('child_process').exec
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
console.log req.body.parameter, req.body.val
|
||||
db.serialize ->
|
||||
query = db.prepare('INSERT INTO config (parameter, val) VALUES (?, ?)')
|
||||
query.run req.body.parameter, req.body.val, (err) ->
|
||||
query.finalize()
|
||||
db.close()
|
||||
if err
|
||||
console.log runErr: err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
query: query
|
||||
else
|
||||
res.redirect '/#/setup'
|
||||
exec '/etc/init.d/loggers stop', (error, stdout, stderr) ->
|
||||
if error
|
||||
console.log
|
||||
status: 'error'
|
||||
message: error
|
||||
query: query
|
||||
setTimeout (->
|
||||
exec '/etc/init.d/loggers start', (error, stdout, stderr) ->
|
||||
if error
|
||||
console.log
|
||||
status: 'error'
|
||||
message: error
|
||||
query: query
|
||||
return
|
||||
return
|
||||
), 5000
|
||||
return
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
exports.clearValues = (req, res) ->
|
||||
sqlite3 = require('sqlite3').verbose()
|
||||
db = new (sqlite3.Database)(dbFile)
|
||||
if req.params.id
|
||||
db.serialize () ->
|
||||
query = 'DELETE FROM tag_vals WHERE tagID = ?;';
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.run req.params.id, (err) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
else
|
||||
db.serialize () ->
|
||||
query = 'DELETE FROM tag_vals WHERE id >= 0;';
|
||||
prepQuery = db.prepare(query)
|
||||
prepQuery.run req.params.id, (err) ->
|
||||
prepQuery.finalize()
|
||||
db.close()
|
||||
if err
|
||||
res.json
|
||||
status: 'error'
|
||||
message: err
|
||||
console.log err
|
||||
else
|
||||
res.json
|
||||
status: 'OK'
|
||||
undefined
|
||||
@@ -14,7 +14,8 @@
|
||||
"serve-favicon": "*",
|
||||
"sqlite3": "*",
|
||||
"n3-charts": "*",
|
||||
"is-running": "*"
|
||||
"is-running": "*",
|
||||
"coffee-script": "*"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
|
||||
15
www/public/css/app.css
Normal file
15
www/public/css/app.css
Normal file
@@ -0,0 +1,15 @@
|
||||
.topMargin40 {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.row-flex {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.row-flex > [class*='col-'] {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -54,12 +54,12 @@ var sqlite_to_dString = function(sqliteDate){
|
||||
};
|
||||
|
||||
var date_to_dString = function(inpDate){
|
||||
var year = inpDate.getUTCFullYear().pad(4);
|
||||
var month = (inpDate.getUTCMonth() + 1).pad(2);
|
||||
var day = inpDate.getUTCDate().pad(2);
|
||||
var hour = inpDate.getUTCHours().pad(2);
|
||||
var min = inpDate.getUTCMinutes().pad(2);
|
||||
var sec = inpDate.getUTCSeconds().pad(2);
|
||||
var year = inpDate.getFullYear().pad(4);
|
||||
var month = (inpDate.getMonth() + 1).pad(2);
|
||||
var day = inpDate.getDate().pad(2);
|
||||
var hour = inpDate.getHours().pad(2);
|
||||
var min = inpDate.getMinutes().pad(2);
|
||||
var sec = inpDate.getSeconds().pad(2);
|
||||
return "".concat(year, month, day, "_", hour, min, sec);
|
||||
};
|
||||
|
||||
@@ -195,11 +195,13 @@ tsCtrlrs.factory('tags',function($q, $http, $log){
|
||||
|
||||
var createTag = function(tag){
|
||||
$http.post('/json/tag/add', {
|
||||
tagName: tag.tagName,
|
||||
vanityName: tag.vanityName,
|
||||
tag: tag.tag,
|
||||
name: tag.name,
|
||||
units: tag.units,
|
||||
minExpected: tag.minExpected,
|
||||
maxExpected: tag.maxExpected,
|
||||
guarantee_sec: tag.guarantee_sec,
|
||||
change_threshold: tag.change_threshold,
|
||||
description: tag.description
|
||||
}).success(function(data){
|
||||
return data;
|
||||
@@ -210,11 +212,13 @@ tsCtrlrs.factory('tags',function($q, $http, $log){
|
||||
$log.info("updateTag called with "+ JSON.stringify(tag));
|
||||
$http.post('/json/tag/update', {
|
||||
id: tag.id,
|
||||
tagName: tag.tagName,
|
||||
vanityName: tag.vanityName,
|
||||
tag: tag.tag,
|
||||
name: tag.name,
|
||||
units: tag.units,
|
||||
minExpected: tag.minExpected,
|
||||
maxExpected: tag.maxExpected,
|
||||
guarantee_sec: tag.guarantee_sec,
|
||||
change_threshold: tag.change_threshold,
|
||||
description: tag.description
|
||||
}).success(function(data){
|
||||
return data;
|
||||
@@ -234,6 +238,28 @@ tsCtrlrs.factory('tags',function($q, $http, $log){
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
var clearSingleTagData = function(id){
|
||||
var deferred = $q.defer();
|
||||
var url = '/json/clearDatabase/' + id;
|
||||
$http.get(url).success(function(data) {
|
||||
deferred.resolve({
|
||||
status: data.status
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
var clearAllTagData = function(){
|
||||
var deferred = $q.defer();
|
||||
var url = '/json/clearDatabase/all';
|
||||
$http.get(url).success(function(data) {
|
||||
deferred.resolve({
|
||||
status: data.status
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
return {
|
||||
getTag: getTag,
|
||||
getTagList: getTagList,
|
||||
@@ -243,6 +269,8 @@ tsCtrlrs.factory('tags',function($q, $http, $log){
|
||||
createTag: createTag,
|
||||
updateTag: updateTag,
|
||||
deleteTag: deleteTag,
|
||||
clearSingleTagData: clearSingleTagData,
|
||||
clearAllTagData: clearAllTagData
|
||||
};
|
||||
});
|
||||
|
||||
@@ -396,6 +424,32 @@ tsCtrlrs.controller('tagsCtrl', function($scope, $route, $http, $routeParams, Pa
|
||||
});
|
||||
};
|
||||
|
||||
$scope.openClearTagData = function(id){
|
||||
var getTag = tags.getTag(id);
|
||||
getTag.then(function(data){
|
||||
if (data.status == "OK"){
|
||||
$scope.error = false;
|
||||
$scope.dTagValues = data.tag;
|
||||
$log.info("Thinking about deleting tag data with parameters: "+ JSON.stringify($scope.dTagValues));
|
||||
} else {
|
||||
$scope.error = data.message;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.deleteTagValues = function(id){
|
||||
var clearSingleTagData = tags.clearSingleTagData(id);
|
||||
clearSingleTagData.then(function(data){
|
||||
$log.info("deleting tag "+ id + " status: " + data.status);
|
||||
if (data.status == "OK"){
|
||||
$scope.error = false;
|
||||
$scope.loadTagList();
|
||||
} else {
|
||||
$scope.error = data.message;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.openEditTag = function(id){
|
||||
var getTag = tags.getTag(id);
|
||||
getTag.then(function(data){
|
||||
@@ -448,7 +502,7 @@ tsCtrlrs.controller('tagValsCtrl', function($scope, $route, $http, $routeParams,
|
||||
if (data.status == "OK"){
|
||||
$scope.data = data;
|
||||
$scope.data.vals = $scope.data.vals.map(function(x){
|
||||
return {id: x.id, tagID: x.tagID, val: x.val, dateAdded: new Date(x.dateAdded)};
|
||||
return {id: x.id, tagID: x.tagID, val: x.val, dtime: new Date(x.dtime)};
|
||||
});
|
||||
$scope.error = false;
|
||||
|
||||
@@ -466,7 +520,7 @@ tsCtrlrs.controller('tagValsCtrl', function($scope, $route, $http, $routeParams,
|
||||
],
|
||||
axes: {
|
||||
x: {
|
||||
key: "dateAdded",
|
||||
key: "dtime",
|
||||
type: "date"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,14 +21,16 @@
|
||||
<div ng-if="!error" class="container">
|
||||
<div class="row">
|
||||
<button ng-click="loadDashboard()" class="btn btn-large btn-success"><i class="fa fa-refresh"></i> Reload Dashboard</button>
|
||||
<a href="/json/csv/all" class="btn btn-large btn-primary"><i class="fa fa-download"></i> Download All Data</a>
|
||||
<div ng-repeat="val in vals">
|
||||
<div class="col-md-4" style="height:200px; margin-bottom:40px;">
|
||||
<just-gage id="{{val.vanityName}}" min='val.min' max='val.max' value='val.val' options="{label:val.units,title:val.vanityName, decimals:2, refreshAnimationType:'bounce', startAnimationType:'bounce'}"></just-gage>
|
||||
<just-gage id="{{val.name}}" min='val.min' max='val.max' value='val.val' options="{label:val.units,title:val.name, decimals:2, refreshAnimationType:'bounce', startAnimationType:'bounce'}"></just-gage>
|
||||
<div style="text-align:center">
|
||||
<h5>{{ val.dtime | date: 'medium'}}</h5>
|
||||
<a href="/#/tag/{{val.t_id}}" class="btn btn-large btn-primary"><i class="fa fa-line-chart"></i> View Data</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -32,19 +32,31 @@
|
||||
<div ng-if="!error" class="container">
|
||||
<div class="row" style="margin-bottom:20px;">
|
||||
<div class="col-md-12">
|
||||
<h1>{{tag.vanityName}}</h1>
|
||||
<span class="timeLabel">From: </span><quick-datepicker ng-model='startDatetime'></quick-datepicker> <span class="timeLabel">To: </span><quick-datepicker ng-model='endDatetime'></quick-datepicker> <button ng-click="loadTagVals(startDatetime, endDatetime)" class="btn btn-large btn-success padMe"><i class="fa fa-refresh"></i> Reload Values</button>
|
||||
<h1>{{tag.name}}</h1>
|
||||
<div class="row row-flex">
|
||||
<div class="col-md-4">
|
||||
<span class="timeLabel">From: </span><quick-datepicker ng-model='startDatetime'></quick-datepicker>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<span class="timeLabel">To: </span><quick-datepicker ng-model='endDatetime'></quick-datepicker>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<button ng-click="loadTagVals(startDatetime, endDatetime)" class="btn btn-large btn-success padMe"><i class="fa fa-refresh"></i> Reload Values</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
<a href="/json/CSV/{{tag.id}}/{{startDatetime | dString}}/{{endDatetime | dString }}" class="btn btn-large btn-primary padMe"><i class="fa fa-download"></i> Download Data</a>
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12">
|
||||
<div class="tagChart" style="height:400px;">
|
||||
<linechart data="data" options="options"></linechart>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
</div>
|
||||
|
||||
<div class="row topMargin40">
|
||||
<div class="col-md-6">
|
||||
<a href="/json/CSV/{{tag.id}}/{{startDatetime | dString}}/{{endDatetime | dString }}" class="btn btn-large btn-primary padMe"><i class="fa fa-download"></i> Download Data</a>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -57,7 +69,7 @@
|
||||
<tr ng-repeat="val in data.vals">
|
||||
<td>{{val.id}}</td>
|
||||
<td>{{val.val}} {{tag.units}}</td>
|
||||
<td>{{val.dateAdded | sqlite_to_local}}</td>
|
||||
<td>{{val.dtime | date:'short'}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -1,109 +1,166 @@
|
||||
<div class="modal fade" id="addModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">Add a New Tag...</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="well" ng-if="message"><h3 class="text-danger">{{message}}</h3></div>
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label for="tagName">Tag Name</label>
|
||||
<input type="text" ng-model="newTag.tagName" class="form-control" id="tagName" placeholder="Tag Name Here">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="vanityName">Vanity Name</label>
|
||||
<input type="text" ng-model="newTag.vanityName" class="form-control" id="vanityName" placeholder="Vanity Name Here">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description">Description</label>
|
||||
<input type="textarea" ng-model="newTag.description" class="form-control" id="description" placeholder="Tag Description Here">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="minExpected">Minimum Value Expected</label>
|
||||
<input type="number" ng-model="newTag.minExpected" class="form-control" id="minExpected" placeholder="0">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="maxExpected">Maximum Value Expected</label>
|
||||
<input type="number" ng-model="newTag.maxExpected" class="form-control" id="maxExpected" placeholder="100">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="units">Units</label>
|
||||
<input type="text" ng-model="newTag.units" class="form-control" id="units" placeholder="lbs, PSI, in, etc.">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" ng-click="submitAddTag();" data-dismiss="modal">Add Tag</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">Add a New Tag...</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="well" ng-if="message"><h3 class="text-danger">{{message}}</h3></div>
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label for="tag">Tag</label>
|
||||
<input type="text" ng-model="newTag.tag" class="form-control" id="tag" placeholder="Tag Name Here">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" ng-model="newTag.name" class="form-control" id="name" placeholder="Vanity Name Here">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description">Description</label>
|
||||
<input type="textarea" ng-model="newTag.description" class="form-control" id="description" placeholder="Tag Description Here">
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="form-group">
|
||||
<label for="minExpected">Minimum Value Expected</label>
|
||||
<input type="number" ng-model="newTag.minExpected" class="form-control" id="minExpected" placeholder="0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="form-group">
|
||||
<label for="maxExpected">Maximum Value Expected</label>
|
||||
<input type="number" ng-model="newTag.maxExpected" class="form-control" id="maxExpected" placeholder="100">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<label for="units">Units</label>
|
||||
<input type="text" ng-model="newTag.units" class="form-control" id="units" placeholder="lbs, PSI, in, etc.">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="change_threshold">Change Threshold</label>
|
||||
<input type="number" ng-model="newTag.change_threshold" class="form-control" id="change_threshold" placeholder="0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="guarantee_sec">Guarantee Sec.</label>
|
||||
<input type="number" ng-model="newTag.guarantee_sec" class="form-control" id="guarantee_sec" placeholder="3600">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" ng-click="submitAddTag();" data-dismiss="modal">Add Tag</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
|
||||
<div class="modal fade" id="editModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">Edit a Tag...</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="well" ng-if="message"><h3 class="text-danger">{{message}}</h3></div>
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label for="tagName">Tag Name</label>
|
||||
<input type="text" ng-model="editTag.tagName" class="form-control" id="tagName" placeholder="Tag Name Here">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="vanityName">Vanity Name</label>
|
||||
<input type="text" ng-model="editTag.vanityName" class="form-control" id="vanityName" placeholder="Vanity Name Here">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description">Description</label>
|
||||
<input type="textarea" ng-model="editTag.description" class="form-control" id="description" placeholder="Tag Description Here">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="minExpected">Minimum Value Expected</label>
|
||||
<input type="number" ng-model="editTag.minExpected" class="form-control" id="minExpected" placeholder="0">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="maxExpected">Maximum Value Expected</label>
|
||||
<input type="number" ng-model="editTag.maxExpected" class="form-control" id="maxExpected" placeholder="100">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="units">Units</label>
|
||||
<input type="text" ng-model="editTag.units" class="form-control" id="units" placeholder="lbs, PSI, in, etc.">
|
||||
</div>
|
||||
</form>
|
||||
<pre>{{editTag}}</pre>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" ng-click="submitEditTag();" data-dismiss="modal">Submit Tag Edits</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">Edit a Tag...</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="well" ng-if="message"><h3 class="text-danger">{{message}}</h3></div>
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label for="tag">Tag Name</label>
|
||||
<input type="text" ng-model="editTag.tag" class="form-control" id="tag" placeholder="Tag Name Here">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="name">Vanity Name</label>
|
||||
<input type="text" ng-model="editTag.name" class="form-control" id="name" placeholder="Vanity Name Here">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description">Description</label>
|
||||
<input type="textarea" ng-model="editTag.description" class="form-control" id="description" placeholder="Tag Description Here">
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="form-group">
|
||||
<label for="minExpected">Minimum Value Expected</label>
|
||||
<input type="number" ng-model="editTag.minExpected" class="form-control" id="minExpected" placeholder="0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="form-group">
|
||||
<label for="maxExpected">Maximum Value Expected</label>
|
||||
<input type="number" ng-model="editTag.maxExpected" class="form-control" id="maxExpected" placeholder="100">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<label for="units">Units</label>
|
||||
<input type="text" ng-model="editTag.units" class="form-control" id="units" placeholder="lbs, PSI, in, etc.">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="change_threshold">Change Threshold</label>
|
||||
<input type="number" ng-model="editTag.change_threshold" class="form-control" id="change_threshold" placeholder="0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="guarantee_sec">Guarantee Sec.</label>
|
||||
<input type="number" ng-model="editTag.guarantee_sec" class="form-control" id="guarantee_sec" placeholder="3600">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<pre>{{editTag}}</pre>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" ng-click="submitEditTag();" data-dismiss="modal">Submit Tag Edits</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
|
||||
<div class="modal fade" id="deleteModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">Are you sure?</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="well" ng-if="message"><h3 class="text-danger">{{message}}</h3></div>
|
||||
<h3>Are you sure you want to delete the tag {{dTag.vanityName}} ({{dTag.tagName}})?</h3>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">NO!!!!!!</button>
|
||||
<button type="button" class="btn btn-danger" ng-click="deleteTag(dTag.id);" data-dismiss="modal">Heck yes, delete it!</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">Are you sure?</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="well" ng-if="message"><h3 class="text-danger">{{message}}</h3></div>
|
||||
<h3>Are you sure you want to delete the tag {{dTag.name}} ({{dTag.tag}})?</h3>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">NO!!!!!!</button>
|
||||
<button type="button" class="btn btn-danger" ng-click="deleteTag(dTag.id);" data-dismiss="modal">Heck yes, delete it!</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<div class="modal fade" id="clearTagDataModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">Are you sure?</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="well" ng-if="message"><h3 class="text-danger">{{message}}</h3></div>
|
||||
<h3>Are you sure you want to delete the data for tag {{dTagValues.name}} ({{dTagValues.tag}})?</h3>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">NO!!!!!!</button>
|
||||
<button type="button" class="btn btn-danger" ng-click="deleteTagValues(dTagValues.id);" data-dismiss="modal">Heck yes, delete it!</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
|
||||
@@ -140,17 +197,19 @@
|
||||
<td>Max Expected Value</td>
|
||||
<td>Units</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="tag in tags">
|
||||
<td>{{tag.id}}</td>
|
||||
<td><a href="/#/tag/{{tag.id}}">{{tag.vanityName}}</a> <i class="fa fa-info-circle" data-toggle="popover" title="{{tag.vanityName}}" data-content="Tag Name: {{tag.tagName}} </br>Details: {{tag.description}}"></i></td>
|
||||
<td><a href="/#/tag/{{tag.id}}">{{tag.name}}</a> <i class="fa fa-info-circle" data-toggle="popover" title="{{tag.name}}" data-content="Tag Name: {{tag.tag}} </br>Details: {{tag.description}}"></i></td>
|
||||
<td>{{tag.minExpected}}</td>
|
||||
<td>{{tag.maxExpected}}</td>
|
||||
<td>{{tag.units}}</td>
|
||||
<td><button data-toggle="modal" data-target="#editModal" ng-click="openEditTag(tag.id)" class="btn btn-primary">Edit</button></td>
|
||||
<td><button data-toggle="modal" data-target="#clearTagDataModal" ng-click="openClearTagData(tag.id)" class="btn btn-primary">Clear Data</button></td>
|
||||
<td><button data-toggle="modal" data-target="#deleteModal" ng-click="openDeleteTag(tag.id)" class="btn btn-danger">Delete</button></td>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
@@ -167,6 +226,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<script src="/bower_components/ngQuickDate/dist/ng-quick-date.min.js"></script>
|
||||
<link rel="stylesheet" href="/bower_components/ngQuickDate/dist/ng-quick-date.css">
|
||||
<link rel="stylesheet" href="/bower_components/ngQuickDate/dist/ng-quick-date-default-theme.css">
|
||||
<link rel="stylesheet" href="/css/app.css">
|
||||
|
||||
<script src="/js/router.js"></script>
|
||||
<script src="/js/controller.js"></script>
|
||||
@@ -43,7 +44,7 @@
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" rel="home" href="/" title="Henry Pump">
|
||||
<a class="navbar-brand" rel="home" href="/#/" title="Henry Pump">
|
||||
<img style="max-width:100px; "src="/img/logo.png">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user