added driver updates
This commit is contained in:
BIN
Pub_Sub/abbflow/.DS_Store
vendored
BIN
Pub_Sub/abbflow/.DS_Store
vendored
Binary file not shown.
@@ -238,7 +238,7 @@
|
|||||||
"alarms": [],
|
"alarms": [],
|
||||||
"misc": {
|
"misc": {
|
||||||
"maxAlarmRecordSz": 2000,
|
"maxAlarmRecordSz": 2000,
|
||||||
"logLvl": "DEBUG",
|
"logLvl": "INFO",
|
||||||
"coms": [
|
"coms": [
|
||||||
{
|
{
|
||||||
"name": "rs232",
|
"name": "rs232",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# Enter your python code.
|
# Enter your python code.
|
||||||
import json, os
|
import json, os
|
||||||
from datetime import datetime as dt
|
from datetime import datetime as dt
|
||||||
|
from datetime import timedelta as td
|
||||||
from common.Logger import logger
|
from common.Logger import logger
|
||||||
from quickfaas.remotebus import publish
|
from quickfaas.remotebus import publish
|
||||||
from quickfaas.global_dict import get as get_params
|
from quickfaas.global_dict import get as get_params
|
||||||
@@ -16,12 +17,12 @@ def reboot(reason="Rebooting for config file update"):
|
|||||||
def checkFileExist(filename):
|
def checkFileExist(filename):
|
||||||
path = "/var/user/files"
|
path = "/var/user/files"
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
logger.info("no folder making files folder in var/user")
|
logger.debug("no folder making files folder in var/user")
|
||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
with open(path + "/" + filename, "a") as f:
|
with open(path + "/" + filename, "a") as f:
|
||||||
json.dump({}, f)
|
json.dump({}, f)
|
||||||
if not os.path.exists(path + "/" + filename):
|
if not os.path.exists(path + "/" + filename):
|
||||||
logger.info("no creds file making creds file")
|
logger.debug("no creds file making creds file")
|
||||||
with open(path + "/" + filename, "a") as f:
|
with open(path + "/" + filename, "a") as f:
|
||||||
json.dump({}, f)
|
json.dump({}, f)
|
||||||
|
|
||||||
@@ -38,21 +39,21 @@ def convertJSONtoDS(j):
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
def checkCredentialConfig():
|
def checkCredentialConfig():
|
||||||
logger.info("CHECKING CONFIG")
|
logger.debug("CHECKING CONFIG")
|
||||||
cfgpath = "/var/user/cfg/device_supervisor/device_supervisor.cfg"
|
cfgpath = "/var/user/cfg/device_supervisor/device_supervisor.cfg"
|
||||||
credspath = "/var/user/files/creds.json"
|
credspath = "/var/user/files/creds.json"
|
||||||
cfg = dict()
|
cfg = dict()
|
||||||
with open(cfgpath, "r") as f:
|
with open(cfgpath, "r") as f:
|
||||||
cfg = json.load(f)
|
cfg = json.load(f)
|
||||||
clouds = cfg.get("clouds")
|
clouds = cfg.get("clouds")
|
||||||
logger.info(clouds)
|
logger.debug(clouds)
|
||||||
#if not configured then try to configure from stored values
|
#if not configured then try to configure from stored values
|
||||||
if clouds[0]["args"]["clientId"] == "unknown" or clouds[0]["args"]["username"] == "unknown" or not clouds[0]["args"]["passwd"] or clouds[0]["args"]["passwd"] == "unknown":
|
if clouds[0]["args"]["clientId"] == "unknown" or clouds[0]["args"]["username"] == "unknown" or not clouds[0]["args"]["passwd"] or clouds[0]["args"]["passwd"] == "unknown":
|
||||||
checkFileExist("creds.json")
|
checkFileExist("creds.json")
|
||||||
with open(credspath, "r") as c:
|
with open(credspath, "r") as c:
|
||||||
creds = json.load(c)
|
creds = json.load(c)
|
||||||
if creds:
|
if creds:
|
||||||
logger.info("updating config with stored data")
|
logger.debug("updating config with stored data")
|
||||||
clouds[0]["args"]["clientId"] = creds["clientId"]
|
clouds[0]["args"]["clientId"] = creds["clientId"]
|
||||||
clouds[0]["args"]["username"] = creds["userName"]
|
clouds[0]["args"]["username"] = creds["userName"]
|
||||||
clouds[0]["args"]["passwd"] = creds["password"]
|
clouds[0]["args"]["passwd"] = creds["password"]
|
||||||
@@ -65,7 +66,7 @@ def checkCredentialConfig():
|
|||||||
#assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data
|
#assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data
|
||||||
checkFileExist("creds.json")
|
checkFileExist("creds.json")
|
||||||
with open(credspath, "r") as c:
|
with open(credspath, "r") as c:
|
||||||
logger.info("updating stored file with new data")
|
logger.debug("updating stored file with new data")
|
||||||
cfg = checkParameterConfig(cfg)
|
cfg = checkParameterConfig(cfg)
|
||||||
with open(cfgpath, "w", encoding='utf-8') as n:
|
with open(cfgpath, "w", encoding='utf-8') as n:
|
||||||
json.dump(cfg, n, indent=1, ensure_ascii=False)
|
json.dump(cfg, n, indent=1, ensure_ascii=False)
|
||||||
@@ -85,20 +86,20 @@ def checkCredentialConfig():
|
|||||||
json.dump(creds,cw)
|
json.dump(creds,cw)
|
||||||
|
|
||||||
def checkParameterConfig(cfg):
|
def checkParameterConfig(cfg):
|
||||||
logger.info("Checking Parameters!!!!")
|
logger.debug("Checking Parameters!!!!")
|
||||||
paramspath = "/var/user/files/params.json"
|
paramspath = "/var/user/files/params.json"
|
||||||
cfgparams = convertDStoJSON(cfg.get("labels"))
|
cfgparams = convertDStoJSON(cfg.get("labels"))
|
||||||
#check stored values
|
#check stored values
|
||||||
checkFileExist("params.json")
|
checkFileExist("params.json")
|
||||||
with open(paramspath, "r") as f:
|
with open(paramspath, "r") as f:
|
||||||
logger.info("Opened param storage file")
|
logger.debug("Opened param storage file")
|
||||||
params = json.load(f)
|
params = json.load(f)
|
||||||
if params:
|
if params:
|
||||||
if cfgparams != params:
|
if cfgparams != params:
|
||||||
#go through each param
|
#go through each param
|
||||||
#if not "unknown" and cfg and params aren't the same take from cfg likely updated manually
|
#if not "unknown" and cfg and params aren't the same take from cfg likely updated manually
|
||||||
#if key in cfg but not in params copy to params
|
#if key in cfg but not in params copy to params
|
||||||
logger.info("equalizing params between cfg and stored")
|
logger.debug("equalizing params between cfg and stored")
|
||||||
for key in cfgparams.keys():
|
for key in cfgparams.keys():
|
||||||
try:
|
try:
|
||||||
if cfgparams[key] != params[key] and cfgparams[key] != "unknown":
|
if cfgparams[key] != params[key] and cfgparams[key] != "unknown":
|
||||||
@@ -111,7 +112,7 @@ def checkParameterConfig(cfg):
|
|||||||
json.dump(params, p)
|
json.dump(params, p)
|
||||||
else:
|
else:
|
||||||
with open(paramspath, "w") as p:
|
with open(paramspath, "w") as p:
|
||||||
logger.info("initializing param file with params in memory")
|
logger.debug("initializing param file with params in memory")
|
||||||
json.dump(convertDStoJSON(get_params()), p)
|
json.dump(convertDStoJSON(get_params()), p)
|
||||||
cfg["labels"] = get_params()
|
cfg["labels"] = get_params()
|
||||||
|
|
||||||
@@ -122,11 +123,11 @@ def get_totalizers():
|
|||||||
with open("/var/user/files/totalizers.json", "r") as t:
|
with open("/var/user/files/totalizers.json", "r") as t:
|
||||||
totalizers = json.load(t)
|
totalizers = json.load(t)
|
||||||
if not totalizers:
|
if not totalizers:
|
||||||
logger.info("-----INITIALIZING TOTALIZERS-----")
|
logger.debug("-----INITIALIZING TOTALIZERS-----")
|
||||||
totalizers = {
|
totalizers = {
|
||||||
"day": 0,
|
"dayDate": "2022-01-01",
|
||||||
"week": 0,
|
"week": 0,
|
||||||
"month": 0,
|
"monthDate": "2022-01-01",
|
||||||
"year": 0,
|
"year": 0,
|
||||||
"lifetime": 0,
|
"lifetime": 0,
|
||||||
"dayHolding": 0,
|
"dayHolding": 0,
|
||||||
@@ -136,9 +137,9 @@ def get_totalizers():
|
|||||||
}
|
}
|
||||||
except:
|
except:
|
||||||
totalizers = {
|
totalizers = {
|
||||||
"day": 0,
|
"dayDate": "2022-01-01",
|
||||||
"week": 0,
|
"week": 0,
|
||||||
"month": 0,
|
"monthDate": "2022-01-01",
|
||||||
"year": 0,
|
"year": 0,
|
||||||
"lifetime": 0,
|
"lifetime": 0,
|
||||||
"dayHolding": 0,
|
"dayHolding": 0,
|
||||||
@@ -158,11 +159,12 @@ def saveTotalizers(totalizers):
|
|||||||
def totalizeDay(lifetime):
|
def totalizeDay(lifetime):
|
||||||
totalizers = get_totalizers()
|
totalizers = get_totalizers()
|
||||||
now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)
|
now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)
|
||||||
|
now = now - td(seconds=60*60*8) #time shifted back 8 hours
|
||||||
reset = False
|
reset = False
|
||||||
value = lifetime - totalizers["dayHolding"]
|
value = lifetime - totalizers["dayHolding"]
|
||||||
if (not int(now.strftime("%d")) == int(totalizers["day"]) and now.hour >= 8 and now.minute == 0) or (abs(int(now.strftime("%d")) - int(totalizers["day"])) > 1 ):
|
if not now.date() == dt.strptime(totalizers["dayDate"], "%Y-%m-%d").date():
|
||||||
totalizers["dayHolding"] = lifetime
|
totalizers["dayHolding"] = lifetime
|
||||||
totalizers["day"] = int(now.strftime("%d"))
|
totalizers["dayDate"] = str(now.date())
|
||||||
saveTotalizers(totalizers)
|
saveTotalizers(totalizers)
|
||||||
reset = True
|
reset = True
|
||||||
return (value,reset)
|
return (value,reset)
|
||||||
@@ -170,11 +172,13 @@ def totalizeDay(lifetime):
|
|||||||
def totalizeMonth(lifetime):
|
def totalizeMonth(lifetime):
|
||||||
totalizers = get_totalizers()
|
totalizers = get_totalizers()
|
||||||
now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)
|
now = dt.fromtimestamp(round(dt.timestamp(dt.now())/600)*600)
|
||||||
|
now = now - td(seconds=60*60*8) #time shifted back 8 hours
|
||||||
|
now = dt.strptime(f"{now.year}-{now.month}", "%Y-%m")
|
||||||
reset = False
|
reset = False
|
||||||
value = lifetime - totalizers["monthHolding"]
|
value = lifetime - totalizers["monthHolding"]
|
||||||
if (not int(now.strftime("%m")) == int(totalizers["month"]) and now.hour >= 8 and now.minute == 0) or (abs(int(now.strftime("%m")) - int(totalizers["month"])) > 1 ):
|
if not now.date() == dt.strptime(totalizers["monthDate"], "%Y-%m-%d").date():
|
||||||
totalizers["monthHolding"] = lifetime
|
totalizers["monthHolding"] = lifetime
|
||||||
totalizers["month"] = now.strftime("%m")
|
totalizers["monthDate"] = str(now.date())
|
||||||
saveTotalizers(totalizers)
|
saveTotalizers(totalizers)
|
||||||
reset = True
|
reset = True
|
||||||
return (value,reset)
|
return (value,reset)
|
||||||
@@ -189,7 +193,7 @@ def sendData(message):
|
|||||||
resetPayload = {"ts": "", "values": {}}
|
resetPayload = {"ts": "", "values": {}}
|
||||||
for measure in message["measures"]:
|
for measure in message["measures"]:
|
||||||
try:
|
try:
|
||||||
if abs(payload["ts"]/1000 - measure["timestamp"]) > 7200:
|
if abs(payload["ts"]/1000 - measure["timestamp"]) > 3600:
|
||||||
reboot(reason="Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}".format(payload["ts"]/1000,measure["timestamp"]))
|
reboot(reason="Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}".format(payload["ts"]/1000,measure["timestamp"]))
|
||||||
|
|
||||||
if measure["name"] in ["accumulated_volume"]:
|
if measure["name"] in ["accumulated_volume"]:
|
||||||
@@ -201,7 +205,10 @@ def sendData(message):
|
|||||||
payload["values"][measure["name"]] = measure["value"]
|
payload["values"][measure["name"]] = measure["value"]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
|
if payload["values"]["today_volume"] < 0:
|
||||||
|
del payload["values"]["today_volume"]
|
||||||
|
if payload["values"]["month_volume"] < 0:
|
||||||
|
del payload["values"]["month_volume"]
|
||||||
publish(__topic__, json.dumps(payload), __qos__)
|
publish(__topic__, json.dumps(payload), __qos__)
|
||||||
publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__)
|
publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__)
|
||||||
|
|
||||||
|
|||||||
BIN
Pub_Sub/abbflow/v2/.DS_Store
vendored
BIN
Pub_Sub/abbflow/v2/.DS_Store
vendored
Binary file not shown.
BIN
Pub_Sub/advvfdipp/.DS_Store
vendored
BIN
Pub_Sub/advvfdipp/.DS_Store
vendored
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -342,7 +342,7 @@ def sendData(message):
|
|||||||
|
|
||||||
if measure["name"] == "vfdfrequency":
|
if measure["name"] == "vfdfrequency":
|
||||||
if measure["value"] > 0:
|
if measure["value"] > 0:
|
||||||
rts.addHertzDataPoint(val)
|
rts.addHertzDataPoint(measure["value"])
|
||||||
rts.saveDataToFile()
|
rts.saveDataToFile()
|
||||||
publish(__topic__ + ":01:99/" + "avgFrequency30Days", json.dumps({"value": rts.calculateAverageHertzMultiDay()}), __qos__)
|
publish(__topic__ + ":01:99/" + "avgFrequency30Days", json.dumps({"value": rts.calculateAverageHertzMultiDay()}), __qos__)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -127,7 +127,7 @@ def sendData(message):
|
|||||||
for measure in message["measures"]:
|
for measure in message["measures"]:
|
||||||
try:
|
try:
|
||||||
logger.debug(measure)
|
logger.debug(measure)
|
||||||
if abs(payload["ts"]/1000 - measure["timestamp"]) > 7200:
|
if abs(payload["ts"]/1000 - measure["timestamp"]) > 3600:
|
||||||
reboot(reason="Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}".format(payload["ts"]/1000,measure["timestamp"]))
|
reboot(reason="Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}".format(payload["ts"]/1000,measure["timestamp"]))
|
||||||
if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]:
|
if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]:
|
||||||
logger.debug("Converting DINT/BOOL to STRING")
|
logger.debug("Converting DINT/BOOL to STRING")
|
||||||
|
|||||||
1221
Pub_Sub/advvfdipp/thingsboard/v4/advvfdipp_tb_v4.cfg
Normal file
1221
Pub_Sub/advvfdipp/thingsboard/v4/advvfdipp_tb_v4.cfg
Normal file
File diff suppressed because one or more lines are too long
201
Pub_Sub/advvfdipp/thingsboard/v4/pub/sendAlarms.py
Normal file
201
Pub_Sub/advvfdipp/thingsboard/v4/pub/sendAlarms.py
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
# Enter your python code.
|
||||||
|
import json, time
|
||||||
|
from common.Logger import logger
|
||||||
|
from quickfaas.remotebus import publish
|
||||||
|
from quickfaas.measure import recall
|
||||||
|
|
||||||
|
|
||||||
|
def sendAlarm(message):
|
||||||
|
logger.info(message)
|
||||||
|
payload = {}
|
||||||
|
payload["ts"] = time.time()*1000
|
||||||
|
payload["values"] = {message["measureName"]: message["value"]}
|
||||||
|
publish(__topic__, json.dumps(payload), __qos__)
|
||||||
|
sync()
|
||||||
|
|
||||||
|
def sync():
|
||||||
|
#get new values and send
|
||||||
|
payload = {"ts": time.time()*1000, "values": {}}
|
||||||
|
try:
|
||||||
|
data = recall()#json.loads(recall().decode("utf-8"))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
logger.debug(data)
|
||||||
|
for controller in data:
|
||||||
|
for measure in controller["measures"]:
|
||||||
|
#publish measure
|
||||||
|
if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]:
|
||||||
|
payload["values"][measure["name"]] = convert_int(measure["name"], measure["value"])
|
||||||
|
payload["values"][measure["name"]+ "_int"] = measure["value"]
|
||||||
|
else:
|
||||||
|
payload["values"][measure["name"]] = measure["value"]
|
||||||
|
logger.debug("Sending on topic: {}".format(__topic__))
|
||||||
|
logger.debug("Sending value: {}".format(payload))
|
||||||
|
publish(__topic__, json.dumps(payload), 1)
|
||||||
|
|
||||||
|
|
||||||
|
def convert_int(plc_tag, value):
|
||||||
|
well_status_codes = {
|
||||||
|
0: "Running",
|
||||||
|
1: "Pumped Off",
|
||||||
|
2: "Alarmed",
|
||||||
|
3: "Locked Out",
|
||||||
|
4: "Stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_control_codes = {
|
||||||
|
0: "Flow",
|
||||||
|
1: "Fluid Level",
|
||||||
|
2: "Tubing Pressure",
|
||||||
|
3: "Manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
downhole_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Connecting",
|
||||||
|
2: "Open Circuit",
|
||||||
|
3: "Shorted",
|
||||||
|
4: "Cannot Decode"
|
||||||
|
}
|
||||||
|
|
||||||
|
permissive_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Flow",
|
||||||
|
2: "Intake Pressure",
|
||||||
|
3: "Intake Temperature",
|
||||||
|
4: "Tubing Pressure",
|
||||||
|
5: "VFD",
|
||||||
|
6: "Fluid Level",
|
||||||
|
7: "Min. Downtime"
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Alarm"
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_vfd_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Locked Out"
|
||||||
|
}
|
||||||
|
|
||||||
|
vfd_fault_codes = {
|
||||||
|
0: "No Fault",
|
||||||
|
2: "Auxiliary Input",
|
||||||
|
3: "Power Loss",
|
||||||
|
4: "UnderVoltage",
|
||||||
|
5: "OverVoltage",
|
||||||
|
7: "Motor Overload",
|
||||||
|
8: "Heatsink OverTemp",
|
||||||
|
9: "Thermister OverTemp",
|
||||||
|
10: "Dynamic Brake OverTemp",
|
||||||
|
12: "Hardware OverCurrent",
|
||||||
|
13: "Ground Fault",
|
||||||
|
14: "Ground Warning",
|
||||||
|
15: "Load Loss",
|
||||||
|
17: "Input Phase Loss",
|
||||||
|
18: "Motor PTC Trip",
|
||||||
|
19: "Task Overrun",
|
||||||
|
20: "Torque Prove Speed Band",
|
||||||
|
21: "Output Phase Loss",
|
||||||
|
24: "Decel Inhibit",
|
||||||
|
25: "OverSpeed Limit",
|
||||||
|
26: "Brake Slipped",
|
||||||
|
27: "Torque Prove Conflict",
|
||||||
|
28: "TP Encls Confict",
|
||||||
|
29: "Analog In Loss",
|
||||||
|
33: "Auto Restarts Exhausted",
|
||||||
|
35: "IPM OverCurrent",
|
||||||
|
36: "SW OverCurrent",
|
||||||
|
38: "Phase U to Ground",
|
||||||
|
39: "Phase V to Ground",
|
||||||
|
40: "Phase W to Ground",
|
||||||
|
41: "Phase UV Short",
|
||||||
|
42: "Phase VW Short",
|
||||||
|
43: "Phase WU Short",
|
||||||
|
44: "Phase UNeg to Ground",
|
||||||
|
45: "Phase VNeg to Ground",
|
||||||
|
46: "Phase WNeg to Ground",
|
||||||
|
48: "System Defaulted",
|
||||||
|
49: "Drive Powerup",
|
||||||
|
51: "Clear Fault Queue",
|
||||||
|
55: "Control Board Overtemp",
|
||||||
|
59: "Invalid Code",
|
||||||
|
61: "Shear Pin 1",
|
||||||
|
62: "Shear Pin 2",
|
||||||
|
64: "Drive Overload",
|
||||||
|
66: "OW Torque Level",
|
||||||
|
67: "Pump Off",
|
||||||
|
71: "Port 1 Adapter",
|
||||||
|
72: "Port 2 Adapter",
|
||||||
|
73: "Port 3 Adapter",
|
||||||
|
74: "Port 4 Adapter",
|
||||||
|
75: "Port 5 Adapter",
|
||||||
|
76: "Port 6 Adapter",
|
||||||
|
77: "IR Volts Range",
|
||||||
|
78: "FluxAmps Ref Range",
|
||||||
|
79: "Excessive Load",
|
||||||
|
80: "AutoTune Aborted",
|
||||||
|
81: "Port 1 DPI Loss",
|
||||||
|
82: "Port 2 DPI Loss",
|
||||||
|
83: "Port 3 DPI Loss",
|
||||||
|
84: "Port 4 DPI Loss",
|
||||||
|
85: "Port 5 DPI Loss",
|
||||||
|
86: "Port 6 DPI Loss",
|
||||||
|
87: "IXo Voltage Range",
|
||||||
|
91: "Primary Velocity Feedback Loss",
|
||||||
|
93: "Hardware Enable Check",
|
||||||
|
94: "Alternate Velocity Feedback Loss",
|
||||||
|
95: "Auxiliary Velocity Feedback Loss",
|
||||||
|
96: "Position Feedback Loss",
|
||||||
|
97: "Auto Tach Switch",
|
||||||
|
100: "Parameter Checksum",
|
||||||
|
101: "Power Down NVS Blank",
|
||||||
|
102: "NVS Not Blank",
|
||||||
|
103: "Power Down NVS Incompatible",
|
||||||
|
104: "Power Board Checksum",
|
||||||
|
106: "Incompat MCB-PB",
|
||||||
|
107: "Replaced MCB-PB",
|
||||||
|
108: "Analog Calibration Checksum",
|
||||||
|
110: "Invalid Power Board Data",
|
||||||
|
111: "Power Board Invalid ID",
|
||||||
|
112: "Power Board App Min Version",
|
||||||
|
113: "Tracking DataError",
|
||||||
|
115: "Power Down Table Full",
|
||||||
|
116: "Power Down Entry Too Large",
|
||||||
|
117: "Power Down Data Checksum",
|
||||||
|
118: "Power Board Power Down Checksum",
|
||||||
|
124: "App ID Changed",
|
||||||
|
125: "Using Backup App",
|
||||||
|
134: "Start on Power Up",
|
||||||
|
137: "External Precharge Error",
|
||||||
|
138: "Precharge Open",
|
||||||
|
141: "Autotune Enc Angle",
|
||||||
|
142: "Autotune Speed Restricted",
|
||||||
|
143: "Autotune Current Regulator",
|
||||||
|
144: "Autotune Inertia",
|
||||||
|
145: "Autotune Travel",
|
||||||
|
13035: "Net IO Timeout",
|
||||||
|
13037: "Net IO Timeout"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
plc_tags = {
|
||||||
|
"wellstatus": well_status_codes.get(value, "Invalid Code"),
|
||||||
|
"pidcontrolmode": pid_control_codes.get(value, "Invalid Code"),
|
||||||
|
"downholesensorstatus": downhole_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmflowrate": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmintakepressure": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmintaketemperature": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmtubingpressure": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmvfd": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmlockout": alarm_vfd_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmfluidlevel": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"runpermissive": permissive_codes.get(value, "Invalid Code"),
|
||||||
|
"startpermissive": permissive_codes.get(value, "Invalid Code"),
|
||||||
|
"last_vfd_fault_code": vfd_fault_codes.get(value, "Invalid Code"),
|
||||||
|
"vfd_fault": vfd_fault_codes.get(value, "Invalid Code"),
|
||||||
|
"flowmeter_fault": alarm_codes.get(value, "Invalid Code")
|
||||||
|
}
|
||||||
|
|
||||||
|
return plc_tags.get(plc_tag, "Invalid Tag")
|
||||||
312
Pub_Sub/advvfdipp/thingsboard/v4/pub/sendData.py
Normal file
312
Pub_Sub/advvfdipp/thingsboard/v4/pub/sendData.py
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
# Enter your python code.
|
||||||
|
import json, os
|
||||||
|
from datetime import datetime as dt
|
||||||
|
from common.Logger import logger
|
||||||
|
from quickfaas.remotebus import publish
|
||||||
|
from quickfaas.global_dict import get as get_params
|
||||||
|
from quickfaas.global_dict import _set_global_args
|
||||||
|
|
||||||
|
def reboot(reason="Rebooting for config file update"):
|
||||||
|
#basic = Basic()
|
||||||
|
logger.info("!" * 10 + "REBOOTING DEVICE" + "!"*10)
|
||||||
|
logger.info(reason)
|
||||||
|
r = os.popen("kill -s SIGHUP `cat /var/run/python/supervisord.pid`").read()
|
||||||
|
logger.info(f"REBOOT : {r}")
|
||||||
|
|
||||||
|
def checkFileExist(filename):
|
||||||
|
path = "/var/user/files"
|
||||||
|
if not os.path.exists(path):
|
||||||
|
logger.debug("no folder making files folder in var/user")
|
||||||
|
os.makedirs(path)
|
||||||
|
with open(path + "/" + filename, "a") as f:
|
||||||
|
json.dump({}, f)
|
||||||
|
if not os.path.exists(path + "/" + filename):
|
||||||
|
logger.debug("no creds file making creds file")
|
||||||
|
with open(path + "/" + filename, "a") as f:
|
||||||
|
json.dump({}, f)
|
||||||
|
|
||||||
|
def convertDStoJSON(ds):
|
||||||
|
j = dict()
|
||||||
|
for x in ds:
|
||||||
|
j[x["key"]] = x["value"]
|
||||||
|
return j
|
||||||
|
|
||||||
|
def convertJSONtoDS(j):
|
||||||
|
d = []
|
||||||
|
for key in j.keys():
|
||||||
|
d.append({"key": key, "value": j[key]})
|
||||||
|
return d
|
||||||
|
|
||||||
|
def checkCredentialConfig():
|
||||||
|
logger.debug("CHECKING CONFIG")
|
||||||
|
cfgpath = "/var/user/cfg/device_supervisor/device_supervisor.cfg"
|
||||||
|
credspath = "/var/user/files/creds.json"
|
||||||
|
cfg = dict()
|
||||||
|
with open(cfgpath, "r") as f:
|
||||||
|
cfg = json.load(f)
|
||||||
|
clouds = cfg.get("clouds")
|
||||||
|
logger.debug(clouds)
|
||||||
|
#if not configured then try to configure from stored values
|
||||||
|
if clouds[0]["args"]["clientId"] == "unknown" or clouds[0]["args"]["username"] == "unknown" or not clouds[0]["args"]["passwd"] or clouds[0]["args"]["passwd"] == "unknown":
|
||||||
|
checkFileExist("creds.json")
|
||||||
|
with open(credspath, "r") as c:
|
||||||
|
creds = json.load(c)
|
||||||
|
if creds:
|
||||||
|
logger.debug("updating config with stored data")
|
||||||
|
clouds[0]["args"]["clientId"] = creds["clientId"]
|
||||||
|
clouds[0]["args"]["username"] = creds["userName"]
|
||||||
|
clouds[0]["args"]["passwd"] = creds["password"]
|
||||||
|
cfg["clouds"] = clouds
|
||||||
|
cfg = checkParameterConfig(cfg)
|
||||||
|
with open(cfgpath, "w", encoding='utf-8') as n:
|
||||||
|
json.dump(cfg, n, indent=1, ensure_ascii=False)
|
||||||
|
reboot()
|
||||||
|
else:
|
||||||
|
#assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data
|
||||||
|
checkFileExist("creds.json")
|
||||||
|
with open(credspath, "r") as c:
|
||||||
|
logger.debug("updating stored file with new data")
|
||||||
|
cfg = checkParameterConfig(cfg)
|
||||||
|
with open(cfgpath, "w", encoding='utf-8') as n:
|
||||||
|
json.dump(cfg, n, indent=1, ensure_ascii=False)
|
||||||
|
creds = json.load(c)
|
||||||
|
if creds:
|
||||||
|
if creds["clientId"] != clouds[0]["args"]["clientId"]:
|
||||||
|
creds["clientId"] = clouds[0]["args"]["clientId"]
|
||||||
|
if creds["userName"] != clouds[0]["args"]["username"]:
|
||||||
|
creds["userName"] = clouds[0]["args"]["username"]
|
||||||
|
if creds["password"] != clouds[0]["args"]["passwd"]:
|
||||||
|
creds["password"] = clouds[0]["args"]["passwd"]
|
||||||
|
else:
|
||||||
|
creds["clientId"] = clouds[0]["args"]["clientId"]
|
||||||
|
creds["userName"] = clouds[0]["args"]["username"]
|
||||||
|
creds["password"] = clouds[0]["args"]["passwd"]
|
||||||
|
with open(credspath, "w") as cw:
|
||||||
|
json.dump(creds,cw)
|
||||||
|
|
||||||
|
def checkParameterConfig(cfg):
|
||||||
|
logger.debug("Checking Parameters!!!!")
|
||||||
|
paramspath = "/var/user/files/params.json"
|
||||||
|
cfgparams = convertDStoJSON(cfg.get("labels"))
|
||||||
|
#check stored values
|
||||||
|
checkFileExist("params.json")
|
||||||
|
with open(paramspath, "r") as f:
|
||||||
|
logger.debug("Opened param storage file")
|
||||||
|
params = json.load(f)
|
||||||
|
if params:
|
||||||
|
if cfgparams != params:
|
||||||
|
#go through each param
|
||||||
|
#if not "unknown" and cfg and params aren't the same take from cfg likely updated manually
|
||||||
|
#if key in cfg but not in params copy to params
|
||||||
|
logger.debug("equalizing params between cfg and stored")
|
||||||
|
for key in cfgparams.keys():
|
||||||
|
try:
|
||||||
|
if cfgparams[key] != params[key] and cfgparams[key] != "unknown":
|
||||||
|
params[key] = cfgparams[key]
|
||||||
|
except:
|
||||||
|
params[key] = cfgparams[key]
|
||||||
|
cfg["labels"] = convertJSONtoDS(params)
|
||||||
|
_set_global_args(convertJSONtoDS(params))
|
||||||
|
with open(paramspath, "w") as p:
|
||||||
|
json.dump(params, p)
|
||||||
|
else:
|
||||||
|
with open(paramspath, "w") as p:
|
||||||
|
logger.debug("initializing param file with params in memory")
|
||||||
|
json.dump(convertDStoJSON(get_params()), p)
|
||||||
|
cfg["labels"] = get_params()
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
def sendData(message):
|
||||||
|
#logger.debug(message)
|
||||||
|
try:
|
||||||
|
checkCredentialConfig()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
payload = {"ts": (round(dt.timestamp(dt.now())/600)*600)*1000, "values": {}}
|
||||||
|
for measure in message["measures"]:
|
||||||
|
try:
|
||||||
|
logger.debug(measure)
|
||||||
|
if abs(payload["ts"]/1000 - measure["timestamp"]) > 3600:
|
||||||
|
reboot(reason="Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}".format(payload["ts"]/1000,measure["timestamp"]))
|
||||||
|
if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]:
|
||||||
|
logger.debug("Converting DINT/BOOL to STRING")
|
||||||
|
value = convert_int(measure["name"], measure["value"])
|
||||||
|
logger.debug("Converted {} to {}".format(measure["value"], value))
|
||||||
|
payload["values"][measure["name"]] = value
|
||||||
|
payload["values"][measure["name"] + "_int"] = measure["value"]
|
||||||
|
else:
|
||||||
|
payload["values"][measure["name"]] = measure["value"]
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
|
||||||
|
publish(__topic__, json.dumps(payload), __qos__)
|
||||||
|
publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__)
|
||||||
|
|
||||||
|
def convert_int(plc_tag, value):
|
||||||
|
well_status_codes = {
|
||||||
|
0: "Running",
|
||||||
|
1: "Pumped Off",
|
||||||
|
2: "Alarmed",
|
||||||
|
3: "Locked Out",
|
||||||
|
4: "Stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_control_codes = {
|
||||||
|
0: "Flow",
|
||||||
|
1: "Fluid Level",
|
||||||
|
2: "Tubing Pressure",
|
||||||
|
3: "Manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
downhole_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Connecting",
|
||||||
|
2: "Open Circuit",
|
||||||
|
3: "Shorted",
|
||||||
|
4: "Cannot Decode"
|
||||||
|
}
|
||||||
|
|
||||||
|
permissive_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Flow",
|
||||||
|
2: "Intake Pressure",
|
||||||
|
3: "Intake Temperature",
|
||||||
|
4: "Tubing Pressure",
|
||||||
|
5: "VFD",
|
||||||
|
6: "Fluid Level",
|
||||||
|
7: "Min. Downtime"
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Alarm"
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_vfd_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Locked Out"
|
||||||
|
}
|
||||||
|
|
||||||
|
vfd_fault_codes = {
|
||||||
|
0: "No Fault",
|
||||||
|
2: "Auxiliary Input",
|
||||||
|
3: "Power Loss",
|
||||||
|
4: "UnderVoltage",
|
||||||
|
5: "OverVoltage",
|
||||||
|
7: "Motor Overload",
|
||||||
|
8: "Heatsink OverTemp",
|
||||||
|
9: "Thermister OverTemp",
|
||||||
|
10: "Dynamic Brake OverTemp",
|
||||||
|
12: "Hardware OverCurrent",
|
||||||
|
13: "Ground Fault",
|
||||||
|
14: "Ground Warning",
|
||||||
|
15: "Load Loss",
|
||||||
|
17: "Input Phase Loss",
|
||||||
|
18: "Motor PTC Trip",
|
||||||
|
19: "Task Overrun",
|
||||||
|
20: "Torque Prove Speed Band",
|
||||||
|
21: "Output Phase Loss",
|
||||||
|
24: "Decel Inhibit",
|
||||||
|
25: "OverSpeed Limit",
|
||||||
|
26: "Brake Slipped",
|
||||||
|
27: "Torque Prove Conflict",
|
||||||
|
28: "TP Encls Confict",
|
||||||
|
29: "Analog In Loss",
|
||||||
|
33: "Auto Restarts Exhausted",
|
||||||
|
35: "IPM OverCurrent",
|
||||||
|
36: "SW OverCurrent",
|
||||||
|
38: "Phase U to Ground",
|
||||||
|
39: "Phase V to Ground",
|
||||||
|
40: "Phase W to Ground",
|
||||||
|
41: "Phase UV Short",
|
||||||
|
42: "Phase VW Short",
|
||||||
|
43: "Phase WU Short",
|
||||||
|
44: "Phase UNeg to Ground",
|
||||||
|
45: "Phase VNeg to Ground",
|
||||||
|
46: "Phase WNeg to Ground",
|
||||||
|
48: "System Defaulted",
|
||||||
|
49: "Drive Powerup",
|
||||||
|
51: "Clear Fault Queue",
|
||||||
|
55: "Control Board Overtemp",
|
||||||
|
59: "Invalid Code",
|
||||||
|
61: "Shear Pin 1",
|
||||||
|
62: "Shear Pin 2",
|
||||||
|
64: "Drive Overload",
|
||||||
|
66: "OW Torque Level",
|
||||||
|
67: "Pump Off",
|
||||||
|
71: "Port 1 Adapter",
|
||||||
|
72: "Port 2 Adapter",
|
||||||
|
73: "Port 3 Adapter",
|
||||||
|
74: "Port 4 Adapter",
|
||||||
|
75: "Port 5 Adapter",
|
||||||
|
76: "Port 6 Adapter",
|
||||||
|
77: "IR Volts Range",
|
||||||
|
78: "FluxAmps Ref Range",
|
||||||
|
79: "Excessive Load",
|
||||||
|
80: "AutoTune Aborted",
|
||||||
|
81: "Port 1 DPI Loss",
|
||||||
|
82: "Port 2 DPI Loss",
|
||||||
|
83: "Port 3 DPI Loss",
|
||||||
|
84: "Port 4 DPI Loss",
|
||||||
|
85: "Port 5 DPI Loss",
|
||||||
|
86: "Port 6 DPI Loss",
|
||||||
|
87: "IXo Voltage Range",
|
||||||
|
91: "Primary Velocity Feedback Loss",
|
||||||
|
93: "Hardware Enable Check",
|
||||||
|
94: "Alternate Velocity Feedback Loss",
|
||||||
|
95: "Auxiliary Velocity Feedback Loss",
|
||||||
|
96: "Position Feedback Loss",
|
||||||
|
97: "Auto Tach Switch",
|
||||||
|
100: "Parameter Checksum",
|
||||||
|
101: "Power Down NVS Blank",
|
||||||
|
102: "NVS Not Blank",
|
||||||
|
103: "Power Down NVS Incompatible",
|
||||||
|
104: "Power Board Checksum",
|
||||||
|
106: "Incompat MCB-PB",
|
||||||
|
107: "Replaced MCB-PB",
|
||||||
|
108: "Analog Calibration Checksum",
|
||||||
|
110: "Invalid Power Board Data",
|
||||||
|
111: "Power Board Invalid ID",
|
||||||
|
112: "Power Board App Min Version",
|
||||||
|
113: "Tracking DataError",
|
||||||
|
115: "Power Down Table Full",
|
||||||
|
116: "Power Down Entry Too Large",
|
||||||
|
117: "Power Down Data Checksum",
|
||||||
|
118: "Power Board Power Down Checksum",
|
||||||
|
124: "App ID Changed",
|
||||||
|
125: "Using Backup App",
|
||||||
|
134: "Start on Power Up",
|
||||||
|
137: "External Precharge Error",
|
||||||
|
138: "Precharge Open",
|
||||||
|
141: "Autotune Enc Angle",
|
||||||
|
142: "Autotune Speed Restricted",
|
||||||
|
143: "Autotune Current Regulator",
|
||||||
|
144: "Autotune Inertia",
|
||||||
|
145: "Autotune Travel",
|
||||||
|
13035: "Net IO Timeout",
|
||||||
|
13037: "Net IO Timeout"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
plc_tags = {
|
||||||
|
"wellstatus": well_status_codes.get(value, "Invalid Code"),
|
||||||
|
"pidcontrolmode": pid_control_codes.get(value, "Invalid Code"),
|
||||||
|
"downholesensorstatus": downhole_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmflowrate": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmintakepressure": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmintaketemperature": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmtubingpressure": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmvfd": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmlockout": alarm_vfd_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmfluidlevel": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"runpermissive": permissive_codes.get(value, "Invalid Code"),
|
||||||
|
"startpermissive": permissive_codes.get(value, "Invalid Code"),
|
||||||
|
"last_vfd_fault_code": vfd_fault_codes.get(value, "Invalid Code"),
|
||||||
|
"vfd_fault": vfd_fault_codes.get(value, "Invalid Code"),
|
||||||
|
"flowmeter_fault": alarm_codes.get(value, "Invalid Code")
|
||||||
|
}
|
||||||
|
|
||||||
|
return plc_tags.get(plc_tag, "Invalid Tag")
|
||||||
|
|
||||||
|
|
||||||
266
Pub_Sub/advvfdipp/thingsboard/v4/sub/receiveCommand.py
Normal file
266
Pub_Sub/advvfdipp/thingsboard/v4/sub/receiveCommand.py
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
import json, time
|
||||||
|
from quickfaas.measure import recall, write
|
||||||
|
from quickfaas.remotebus import publish
|
||||||
|
from common.Logger import logger
|
||||||
|
|
||||||
|
def sync():
|
||||||
|
#get new values and send
|
||||||
|
payload = {}
|
||||||
|
topic = "v1/devices/me/telemetry"
|
||||||
|
try:
|
||||||
|
data = recall()#json.loads(recall().decode("utf-8"))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
logger.debug(data)
|
||||||
|
for controller in data:
|
||||||
|
for measure in controller["measures"]:
|
||||||
|
#publish measure
|
||||||
|
if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]:
|
||||||
|
payload[measure["name"]] = convert_int(measure["name"], measure["value"])
|
||||||
|
payload[measure["name"]+ "_int"] = measure["value"]
|
||||||
|
else:
|
||||||
|
payload[measure["name"]] = measure["value"]
|
||||||
|
logger.debug("Sending on topic: {}".format(topic))
|
||||||
|
logger.debug("Sending value: {}".format(payload))
|
||||||
|
publish(topic, json.dumps(payload), 1)
|
||||||
|
def writeplctag(value):
|
||||||
|
#value in the form {"measurement": <measurement_name>, "value": <value to write>}
|
||||||
|
try:
|
||||||
|
#value = json.loads(value.replace("'",'"'))
|
||||||
|
logger.debug(value)
|
||||||
|
#payload format: [{"name": "advvfdipp", "measures": [{"name": "manualfrequencysetpoint", "value": 49}]}]
|
||||||
|
message = [{"name": "advvfdipp", "measures":[{"name":value["measurement"], "value": value["value"]}]}]
|
||||||
|
resp = write(message)
|
||||||
|
logger.debug("RETURN FROM WRITE: {}".format(resp))
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def receiveCommand(topic, payload):
|
||||||
|
try:
|
||||||
|
logger.debug(topic)
|
||||||
|
logger.debug(json.loads(payload))
|
||||||
|
p = json.loads(payload)
|
||||||
|
command = p["method"]
|
||||||
|
commands = {
|
||||||
|
"sync": sync,
|
||||||
|
"writeplctag": writeplctag,
|
||||||
|
}
|
||||||
|
if command == "setPLCTag":
|
||||||
|
try:
|
||||||
|
result = commands["writeplctag"](p["params"])
|
||||||
|
logger.debug(result)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
elif command == "changeSetpoint":
|
||||||
|
try:
|
||||||
|
logger.debug("attempting controlpoint write")
|
||||||
|
params_type = {"measurement": "pidcontrolmode", "value": p["params"]["setpointType"]}
|
||||||
|
if params_type["value"]:
|
||||||
|
commands["writeplctag"](params_type)
|
||||||
|
time.sleep(2)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("DID NOT WRITE CONTROL MODE")
|
||||||
|
logger.error(e)
|
||||||
|
try:
|
||||||
|
logger.debug("attempting setpoint write")
|
||||||
|
modes = {0: "flowsetpoint", 1: "fluidlevelsetpoint", 2: "tubingpressuresetpoint", 3: "manualfrequencysetpoint"}
|
||||||
|
params_value = {"value": p["params"]["setpointValue"]}
|
||||||
|
if params_value["value"]:
|
||||||
|
params_value["measurement"] = modes[getMode()]
|
||||||
|
result = commands["writeplctag"](params_value)
|
||||||
|
logger.debug(result)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("DID NOT WRITE SETPOINT")
|
||||||
|
logger.error(e)
|
||||||
|
#logger.debug(command)
|
||||||
|
ack(topic.split("/")[-1])
|
||||||
|
time.sleep(5)
|
||||||
|
sync()
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(e)
|
||||||
|
|
||||||
|
|
||||||
|
def ack(msgid):
|
||||||
|
#logger.debug(msgid)
|
||||||
|
#logger.debug(mac)
|
||||||
|
#logger.debug(name)
|
||||||
|
#logger.debug(value)
|
||||||
|
publish("v1/devices/me/rpc/response/" + str(msgid), json.dumps({"msg": {"time": time.time()}, "metadata": "", "msgType": ""}), 1)
|
||||||
|
|
||||||
|
def getMode():
|
||||||
|
try:
|
||||||
|
data = recall()
|
||||||
|
for controller in data:
|
||||||
|
for measure in controller["measures"]:
|
||||||
|
if measure["name"] == "pidcontrolmode":
|
||||||
|
return measure["value"]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def convert_int(plc_tag, value):
|
||||||
|
well_status_codes = {
|
||||||
|
0: "Running",
|
||||||
|
1: "Pumped Off",
|
||||||
|
2: "Alarmed",
|
||||||
|
3: "Locked Out",
|
||||||
|
4: "Stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_control_codes = {
|
||||||
|
0: "Flow",
|
||||||
|
1: "Fluid Level",
|
||||||
|
2: "Tubing Pressure",
|
||||||
|
3: "Manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
downhole_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Connecting",
|
||||||
|
2: "Open Circuit",
|
||||||
|
3: "Shorted",
|
||||||
|
4: "Cannot Decode"
|
||||||
|
}
|
||||||
|
|
||||||
|
permissive_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Flow",
|
||||||
|
2: "Intake Pressure",
|
||||||
|
3: "Intake Temperature",
|
||||||
|
4: "Tubing Pressure",
|
||||||
|
5: "VFD",
|
||||||
|
6: "Fluid Level",
|
||||||
|
7: "Min. Downtime"
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Alarm"
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_vfd_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Locked Out"
|
||||||
|
}
|
||||||
|
|
||||||
|
vfd_fault_codes = {
|
||||||
|
0: "No Fault",
|
||||||
|
2: "Auxiliary Input",
|
||||||
|
3: "Power Loss",
|
||||||
|
4: "UnderVoltage",
|
||||||
|
5: "OverVoltage",
|
||||||
|
7: "Motor Overload",
|
||||||
|
8: "Heatsink OverTemp",
|
||||||
|
9: "Thermister OverTemp",
|
||||||
|
10: "Dynamic Brake OverTemp",
|
||||||
|
12: "Hardware OverCurrent",
|
||||||
|
13: "Ground Fault",
|
||||||
|
14: "Ground Warning",
|
||||||
|
15: "Load Loss",
|
||||||
|
17: "Input Phase Loss",
|
||||||
|
18: "Motor PTC Trip",
|
||||||
|
19: "Task Overrun",
|
||||||
|
20: "Torque Prove Speed Band",
|
||||||
|
21: "Output Phase Loss",
|
||||||
|
24: "Decel Inhibit",
|
||||||
|
25: "OverSpeed Limit",
|
||||||
|
26: "Brake Slipped",
|
||||||
|
27: "Torque Prove Conflict",
|
||||||
|
28: "TP Encls Confict",
|
||||||
|
29: "Analog In Loss",
|
||||||
|
33: "Auto Restarts Exhausted",
|
||||||
|
35: "IPM OverCurrent",
|
||||||
|
36: "SW OverCurrent",
|
||||||
|
38: "Phase U to Ground",
|
||||||
|
39: "Phase V to Ground",
|
||||||
|
40: "Phase W to Ground",
|
||||||
|
41: "Phase UV Short",
|
||||||
|
42: "Phase VW Short",
|
||||||
|
43: "Phase WU Short",
|
||||||
|
44: "Phase UNeg to Ground",
|
||||||
|
45: "Phase VNeg to Ground",
|
||||||
|
46: "Phase WNeg to Ground",
|
||||||
|
48: "System Defaulted",
|
||||||
|
49: "Drive Powerup",
|
||||||
|
51: "Clear Fault Queue",
|
||||||
|
55: "Control Board Overtemp",
|
||||||
|
59: "Invalid Code",
|
||||||
|
61: "Shear Pin 1",
|
||||||
|
62: "Shear Pin 2",
|
||||||
|
64: "Drive Overload",
|
||||||
|
66: "OW Torque Level",
|
||||||
|
67: "Pump Off",
|
||||||
|
71: "Port 1 Adapter",
|
||||||
|
72: "Port 2 Adapter",
|
||||||
|
73: "Port 3 Adapter",
|
||||||
|
74: "Port 4 Adapter",
|
||||||
|
75: "Port 5 Adapter",
|
||||||
|
76: "Port 6 Adapter",
|
||||||
|
77: "IR Volts Range",
|
||||||
|
78: "FluxAmps Ref Range",
|
||||||
|
79: "Excessive Load",
|
||||||
|
80: "AutoTune Aborted",
|
||||||
|
81: "Port 1 DPI Loss",
|
||||||
|
82: "Port 2 DPI Loss",
|
||||||
|
83: "Port 3 DPI Loss",
|
||||||
|
84: "Port 4 DPI Loss",
|
||||||
|
85: "Port 5 DPI Loss",
|
||||||
|
86: "Port 6 DPI Loss",
|
||||||
|
87: "IXo Voltage Range",
|
||||||
|
91: "Primary Velocity Feedback Loss",
|
||||||
|
93: "Hardware Enable Check",
|
||||||
|
94: "Alternate Velocity Feedback Loss",
|
||||||
|
95: "Auxiliary Velocity Feedback Loss",
|
||||||
|
96: "Position Feedback Loss",
|
||||||
|
97: "Auto Tach Switch",
|
||||||
|
100: "Parameter Checksum",
|
||||||
|
101: "Power Down NVS Blank",
|
||||||
|
102: "NVS Not Blank",
|
||||||
|
103: "Power Down NVS Incompatible",
|
||||||
|
104: "Power Board Checksum",
|
||||||
|
106: "Incompat MCB-PB",
|
||||||
|
107: "Replaced MCB-PB",
|
||||||
|
108: "Analog Calibration Checksum",
|
||||||
|
110: "Invalid Power Board Data",
|
||||||
|
111: "Power Board Invalid ID",
|
||||||
|
112: "Power Board App Min Version",
|
||||||
|
113: "Tracking DataError",
|
||||||
|
115: "Power Down Table Full",
|
||||||
|
116: "Power Down Entry Too Large",
|
||||||
|
117: "Power Down Data Checksum",
|
||||||
|
118: "Power Board Power Down Checksum",
|
||||||
|
124: "App ID Changed",
|
||||||
|
125: "Using Backup App",
|
||||||
|
134: "Start on Power Up",
|
||||||
|
137: "External Precharge Error",
|
||||||
|
138: "Precharge Open",
|
||||||
|
141: "Autotune Enc Angle",
|
||||||
|
142: "Autotune Speed Restricted",
|
||||||
|
143: "Autotune Current Regulator",
|
||||||
|
144: "Autotune Inertia",
|
||||||
|
145: "Autotune Travel",
|
||||||
|
13035: "Net IO Timeout",
|
||||||
|
13037: "Net IO Timeout"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
plc_tags = {
|
||||||
|
"wellstatus": well_status_codes.get(value, "Invalid Code"),
|
||||||
|
"pidcontrolmode": pid_control_codes.get(value, "Invalid Code"),
|
||||||
|
"downholesensorstatus": downhole_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmflowrate": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmintakepressure": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmintaketemperature": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmtubingpressure": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmvfd": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmlockout": alarm_vfd_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmfluidlevel": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"runpermissive": permissive_codes.get(value, "Invalid Code"),
|
||||||
|
"startpermissive": permissive_codes.get(value, "Invalid Code"),
|
||||||
|
"last_vfd_fault_code": vfd_fault_codes.get(value, "Invalid Code"),
|
||||||
|
"vfd_fault": vfd_fault_codes.get(value, "Invalid Code"),
|
||||||
|
"flowmeter_fault": alarm_codes.get(value, "Invalid Code")
|
||||||
|
}
|
||||||
|
|
||||||
|
return plc_tags.get(plc_tag, "Invalid Tag")
|
||||||
@@ -1614,7 +1614,176 @@
|
|||||||
"addr": "30017"
|
"addr": "30017"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"alarms": [],
|
"alarms": [{
|
||||||
|
"name": "alarmflowrate",
|
||||||
|
"ctrlName": "advvfdipp",
|
||||||
|
"measureName": "alarmflowrate",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "Flow Rate Alarm triggered",
|
||||||
|
"alarmLable": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "alarmintakepressure",
|
||||||
|
"ctrlName": "advvfdipp",
|
||||||
|
"measureName": "alarmintakepressure",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "Intake Pressure Alarm triggered",
|
||||||
|
"alarmLable": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "alarmintaketemperature",
|
||||||
|
"ctrlName": "advvfdipp",
|
||||||
|
"measureName": "alarmintaketemperature",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "Intake Temperature Alarm triggered",
|
||||||
|
"alarmLable": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "alarmtubingpressure",
|
||||||
|
"ctrlName": "advvfdipp",
|
||||||
|
"measureName": "alarmtubingpressure",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "Tubing Pressure Alarm triggered",
|
||||||
|
"alarmLable": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "alarmvfd",
|
||||||
|
"ctrlName": "advvfdipp",
|
||||||
|
"measureName": "alarmvfd",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "VFD Alarm triggered",
|
||||||
|
"alarmLable": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "alarmlockout",
|
||||||
|
"ctrlName": "advvfdipp",
|
||||||
|
"measureName": "alarmlockout",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "Lockout Alarm triggered",
|
||||||
|
"alarmLable": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "alarmfluidlevel",
|
||||||
|
"ctrlName": "advvfdipp",
|
||||||
|
"measureName": "alarmfluidlevel",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "Fluid Level Alarm triggered",
|
||||||
|
"alarmLable": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "controllerfault_io",
|
||||||
|
"ctrlName": "advvfdipp",
|
||||||
|
"measureName": "controllerfault_io",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "Controller IO Alarm triggered",
|
||||||
|
"alarmLable": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "controllerfault_program",
|
||||||
|
"ctrlName": "advvfdipp",
|
||||||
|
"measureName": "controllerfault_program",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "Controller Fault Alarm triggered",
|
||||||
|
"alarmLable": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "flowmeter_fault",
|
||||||
|
"ctrlName": "advvfdipp",
|
||||||
|
"measureName": "flowmeter_fault",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "Flow Meter Alarm triggered",
|
||||||
|
"alarmLable": "default"
|
||||||
|
}],
|
||||||
"misc": {
|
"misc": {
|
||||||
"maxAlarmRecordSz": 2000,
|
"maxAlarmRecordSz": 2000,
|
||||||
"logLvl": "INFO",
|
"logLvl": "INFO",
|
||||||
@@ -1699,6 +1868,19 @@
|
|||||||
"script": "# Enter your python code.\nimport json, time\nfrom quickfaas.measure import recall, write\nfrom quickfaas.remotebus import publish\nfrom common.Logger import logger\n\n\ndef writeplctag(value):\n #value in the form {\"measurement\": <measurement_name>, \"value\": <value to write>}\n try:\n #value = json.loads(value.replace(\"'\",'\"'))\n logger.info(value)\n #payload format: [{\"name\": \"advvfdipp\", \"measures\": [{\"name\": \"manualfrequencysetpoint\", \"value\": 49}]}]\n message = [{\"name\": \"advvfdipp\", \"measures\":[{\"name\":value[\"measurement\"], \"value\": value[\"value\"]}]}]\n resp = write(message) \n logger.info(\"RETURN FROM WRITE: {}\".format(resp))\n return True\n except Exception as e:\n logger.info(e)\n return False\n\ndef sendToPLC(message):\n logger.info(message)\n for measure in message[\"measures\"]:\n logger.info(measure)\n #{'ctrlName': 'modbus_converter', 'name': 'SRU_Data[1]', 'health': 1, 'timestamp': 1664894200, 'value': 47}\n writeplctag({\"measurement\": measure[\"name\"], \"value\": measure[\"value\"]})\n #time.sleep(2)\n ",
|
"script": "# Enter your python code.\nimport json, time\nfrom quickfaas.measure import recall, write\nfrom quickfaas.remotebus import publish\nfrom common.Logger import logger\n\n\ndef writeplctag(value):\n #value in the form {\"measurement\": <measurement_name>, \"value\": <value to write>}\n try:\n #value = json.loads(value.replace(\"'\",'\"'))\n logger.info(value)\n #payload format: [{\"name\": \"advvfdipp\", \"measures\": [{\"name\": \"manualfrequencysetpoint\", \"value\": 49}]}]\n message = [{\"name\": \"advvfdipp\", \"measures\":[{\"name\":value[\"measurement\"], \"value\": value[\"value\"]}]}]\n resp = write(message) \n logger.info(\"RETURN FROM WRITE: {}\".format(resp))\n return True\n except Exception as e:\n logger.info(e)\n return False\n\ndef sendToPLC(message):\n logger.info(message)\n for measure in message[\"measures\"]:\n logger.info(measure)\n #{'ctrlName': 'modbus_converter', 'name': 'SRU_Data[1]', 'health': 1, 'timestamp': 1664894200, 'value': 47}\n writeplctag({\"measurement\": measure[\"name\"], \"value\": measure[\"value\"]})\n #time.sleep(2)\n ",
|
||||||
"msgType": 0,
|
"msgType": 0,
|
||||||
"cloudName": "default"
|
"cloudName": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sendAlarm",
|
||||||
|
"trigger": "warning_event",
|
||||||
|
"topic": "v1/devices/me/telemetry",
|
||||||
|
"qos": 1,
|
||||||
|
"funcName": "sendAlarm",
|
||||||
|
"script": "# Enter your python code.\nimport json, time\nfrom common.Logger import logger\nfrom quickfaas.remotebus import publish\n\n\ndef sendAlarm(message):\n logger.info(message)\n payload = {}\n payload[\"ts\"] = time.time()*1000\n payload[\"values\"] = {message[\"measureName\"]: message[\"value\"]}\n publish(__topic__, json.dumps(payload), __qos__)",
|
||||||
|
"alarms": [
|
||||||
|
"default"
|
||||||
|
],
|
||||||
|
"msgType": 0,
|
||||||
|
"cloudName": "default"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"downloadFuncs": [
|
"downloadFuncs": [
|
||||||
@@ -9,20 +9,20 @@ def writeplctag(value):
|
|||||||
#value in the form {"measurement": <measurement_name>, "value": <value to write>}
|
#value in the form {"measurement": <measurement_name>, "value": <value to write>}
|
||||||
try:
|
try:
|
||||||
#value = json.loads(value.replace("'",'"'))
|
#value = json.loads(value.replace("'",'"'))
|
||||||
logger.info(value)
|
logger.debug(value)
|
||||||
#payload format: [{"name": "advvfdipp", "measures": [{"name": "manualfrequencysetpoint", "value": 49}]}]
|
#payload format: [{"name": "advvfdipp", "measures": [{"name": "manualfrequencysetpoint", "value": 49}]}]
|
||||||
message = [{"name": "advvfdipp", "measures":[{"name":value["measurement"], "value": value["value"]}]}]
|
message = [{"name": "advvfdipp", "measures":[{"name":value["measurement"], "value": value["value"]}]}]
|
||||||
resp = write(message)
|
resp = write(message)
|
||||||
logger.info("RETURN FROM WRITE: {}".format(resp))
|
logger.debug("RETURN FROM WRITE: {}".format(resp))
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.info(e)
|
logger.error(e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def sendToPLC(message):
|
def sendToPLC(message):
|
||||||
logger.info(message)
|
logger.debug(message)
|
||||||
for measure in message["measures"]:
|
for measure in message["measures"]:
|
||||||
logger.info(measure)
|
logger.debug(measure)
|
||||||
#{'ctrlName': 'modbus_converter', 'name': 'SRU_Data[1]', 'health': 1, 'timestamp': 1664894200, 'value': 47}
|
#{'ctrlName': 'modbus_converter', 'name': 'SRU_Data[1]', 'health': 1, 'timestamp': 1664894200, 'value': 47}
|
||||||
writeplctag({"measurement": measure["name"], "value": measure["value"]})
|
writeplctag({"measurement": measure["name"], "value": measure["value"]})
|
||||||
#time.sleep(2)
|
#time.sleep(2)
|
||||||
|
|||||||
1960
Pub_Sub/advvfdipp_sru/thingsboard/v2/advvfdipp_sru_tb_v2.cfg
Normal file
1960
Pub_Sub/advvfdipp_sru/thingsboard/v2/advvfdipp_sru_tb_v2.cfg
Normal file
File diff suppressed because one or more lines are too long
201
Pub_Sub/advvfdipp_sru/thingsboard/v2/pub/sendAlarms.py
Normal file
201
Pub_Sub/advvfdipp_sru/thingsboard/v2/pub/sendAlarms.py
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
# Enter your python code.
|
||||||
|
import json, time
|
||||||
|
from common.Logger import logger
|
||||||
|
from quickfaas.remotebus import publish
|
||||||
|
from quickfaas.measure import recall
|
||||||
|
|
||||||
|
|
||||||
|
def sendAlarm(message):
|
||||||
|
logger.info(message)
|
||||||
|
payload = {}
|
||||||
|
payload["ts"] = time.time()*1000
|
||||||
|
payload["values"] = {message["measureName"]: message["value"]}
|
||||||
|
publish(__topic__, json.dumps(payload), __qos__)
|
||||||
|
sync()
|
||||||
|
|
||||||
|
def sync():
|
||||||
|
#get new values and send
|
||||||
|
payload = {"ts": time.time()*1000, "values": {}}
|
||||||
|
try:
|
||||||
|
data = recall()#json.loads(recall().decode("utf-8"))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
logger.debug(data)
|
||||||
|
for controller in data:
|
||||||
|
for measure in controller["measures"]:
|
||||||
|
#publish measure
|
||||||
|
if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]:
|
||||||
|
payload["values"][measure["name"]] = convert_int(measure["name"], measure["value"])
|
||||||
|
payload["values"][measure["name"]+ "_int"] = measure["value"]
|
||||||
|
else:
|
||||||
|
payload["values"][measure["name"]] = measure["value"]
|
||||||
|
logger.debug("Sending on topic: {}".format(__topic__))
|
||||||
|
logger.debug("Sending value: {}".format(payload))
|
||||||
|
publish(__topic__, json.dumps(payload), 1)
|
||||||
|
|
||||||
|
|
||||||
|
def convert_int(plc_tag, value):
|
||||||
|
well_status_codes = {
|
||||||
|
0: "Running",
|
||||||
|
1: "Pumped Off",
|
||||||
|
2: "Alarmed",
|
||||||
|
3: "Locked Out",
|
||||||
|
4: "Stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_control_codes = {
|
||||||
|
0: "Flow",
|
||||||
|
1: "Fluid Level",
|
||||||
|
2: "Tubing Pressure",
|
||||||
|
3: "Manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
downhole_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Connecting",
|
||||||
|
2: "Open Circuit",
|
||||||
|
3: "Shorted",
|
||||||
|
4: "Cannot Decode"
|
||||||
|
}
|
||||||
|
|
||||||
|
permissive_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Flow",
|
||||||
|
2: "Intake Pressure",
|
||||||
|
3: "Intake Temperature",
|
||||||
|
4: "Tubing Pressure",
|
||||||
|
5: "VFD",
|
||||||
|
6: "Fluid Level",
|
||||||
|
7: "Min. Downtime"
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Alarm"
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_vfd_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Locked Out"
|
||||||
|
}
|
||||||
|
|
||||||
|
vfd_fault_codes = {
|
||||||
|
0: "No Fault",
|
||||||
|
2: "Auxiliary Input",
|
||||||
|
3: "Power Loss",
|
||||||
|
4: "UnderVoltage",
|
||||||
|
5: "OverVoltage",
|
||||||
|
7: "Motor Overload",
|
||||||
|
8: "Heatsink OverTemp",
|
||||||
|
9: "Thermister OverTemp",
|
||||||
|
10: "Dynamic Brake OverTemp",
|
||||||
|
12: "Hardware OverCurrent",
|
||||||
|
13: "Ground Fault",
|
||||||
|
14: "Ground Warning",
|
||||||
|
15: "Load Loss",
|
||||||
|
17: "Input Phase Loss",
|
||||||
|
18: "Motor PTC Trip",
|
||||||
|
19: "Task Overrun",
|
||||||
|
20: "Torque Prove Speed Band",
|
||||||
|
21: "Output Phase Loss",
|
||||||
|
24: "Decel Inhibit",
|
||||||
|
25: "OverSpeed Limit",
|
||||||
|
26: "Brake Slipped",
|
||||||
|
27: "Torque Prove Conflict",
|
||||||
|
28: "TP Encls Confict",
|
||||||
|
29: "Analog In Loss",
|
||||||
|
33: "Auto Restarts Exhausted",
|
||||||
|
35: "IPM OverCurrent",
|
||||||
|
36: "SW OverCurrent",
|
||||||
|
38: "Phase U to Ground",
|
||||||
|
39: "Phase V to Ground",
|
||||||
|
40: "Phase W to Ground",
|
||||||
|
41: "Phase UV Short",
|
||||||
|
42: "Phase VW Short",
|
||||||
|
43: "Phase WU Short",
|
||||||
|
44: "Phase UNeg to Ground",
|
||||||
|
45: "Phase VNeg to Ground",
|
||||||
|
46: "Phase WNeg to Ground",
|
||||||
|
48: "System Defaulted",
|
||||||
|
49: "Drive Powerup",
|
||||||
|
51: "Clear Fault Queue",
|
||||||
|
55: "Control Board Overtemp",
|
||||||
|
59: "Invalid Code",
|
||||||
|
61: "Shear Pin 1",
|
||||||
|
62: "Shear Pin 2",
|
||||||
|
64: "Drive Overload",
|
||||||
|
66: "OW Torque Level",
|
||||||
|
67: "Pump Off",
|
||||||
|
71: "Port 1 Adapter",
|
||||||
|
72: "Port 2 Adapter",
|
||||||
|
73: "Port 3 Adapter",
|
||||||
|
74: "Port 4 Adapter",
|
||||||
|
75: "Port 5 Adapter",
|
||||||
|
76: "Port 6 Adapter",
|
||||||
|
77: "IR Volts Range",
|
||||||
|
78: "FluxAmps Ref Range",
|
||||||
|
79: "Excessive Load",
|
||||||
|
80: "AutoTune Aborted",
|
||||||
|
81: "Port 1 DPI Loss",
|
||||||
|
82: "Port 2 DPI Loss",
|
||||||
|
83: "Port 3 DPI Loss",
|
||||||
|
84: "Port 4 DPI Loss",
|
||||||
|
85: "Port 5 DPI Loss",
|
||||||
|
86: "Port 6 DPI Loss",
|
||||||
|
87: "IXo Voltage Range",
|
||||||
|
91: "Primary Velocity Feedback Loss",
|
||||||
|
93: "Hardware Enable Check",
|
||||||
|
94: "Alternate Velocity Feedback Loss",
|
||||||
|
95: "Auxiliary Velocity Feedback Loss",
|
||||||
|
96: "Position Feedback Loss",
|
||||||
|
97: "Auto Tach Switch",
|
||||||
|
100: "Parameter Checksum",
|
||||||
|
101: "Power Down NVS Blank",
|
||||||
|
102: "NVS Not Blank",
|
||||||
|
103: "Power Down NVS Incompatible",
|
||||||
|
104: "Power Board Checksum",
|
||||||
|
106: "Incompat MCB-PB",
|
||||||
|
107: "Replaced MCB-PB",
|
||||||
|
108: "Analog Calibration Checksum",
|
||||||
|
110: "Invalid Power Board Data",
|
||||||
|
111: "Power Board Invalid ID",
|
||||||
|
112: "Power Board App Min Version",
|
||||||
|
113: "Tracking DataError",
|
||||||
|
115: "Power Down Table Full",
|
||||||
|
116: "Power Down Entry Too Large",
|
||||||
|
117: "Power Down Data Checksum",
|
||||||
|
118: "Power Board Power Down Checksum",
|
||||||
|
124: "App ID Changed",
|
||||||
|
125: "Using Backup App",
|
||||||
|
134: "Start on Power Up",
|
||||||
|
137: "External Precharge Error",
|
||||||
|
138: "Precharge Open",
|
||||||
|
141: "Autotune Enc Angle",
|
||||||
|
142: "Autotune Speed Restricted",
|
||||||
|
143: "Autotune Current Regulator",
|
||||||
|
144: "Autotune Inertia",
|
||||||
|
145: "Autotune Travel",
|
||||||
|
13035: "Net IO Timeout",
|
||||||
|
13037: "Net IO Timeout"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
plc_tags = {
|
||||||
|
"wellstatus": well_status_codes.get(value, "Invalid Code"),
|
||||||
|
"pidcontrolmode": pid_control_codes.get(value, "Invalid Code"),
|
||||||
|
"downholesensorstatus": downhole_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmflowrate": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmintakepressure": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmintaketemperature": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmtubingpressure": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmvfd": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmlockout": alarm_vfd_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmfluidlevel": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"runpermissive": permissive_codes.get(value, "Invalid Code"),
|
||||||
|
"startpermissive": permissive_codes.get(value, "Invalid Code"),
|
||||||
|
"last_vfd_fault_code": vfd_fault_codes.get(value, "Invalid Code"),
|
||||||
|
"vfd_fault": vfd_fault_codes.get(value, "Invalid Code"),
|
||||||
|
"flowmeter_fault": alarm_codes.get(value, "Invalid Code")
|
||||||
|
}
|
||||||
|
|
||||||
|
return plc_tags.get(plc_tag, "Invalid Tag")
|
||||||
312
Pub_Sub/advvfdipp_sru/thingsboard/v2/pub/sendData.py
Normal file
312
Pub_Sub/advvfdipp_sru/thingsboard/v2/pub/sendData.py
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
# Enter your python code.
|
||||||
|
import json, os
|
||||||
|
from datetime import datetime as dt
|
||||||
|
from common.Logger import logger
|
||||||
|
from quickfaas.remotebus import publish
|
||||||
|
from quickfaas.global_dict import get as get_params
|
||||||
|
from quickfaas.global_dict import _set_global_args
|
||||||
|
|
||||||
|
def reboot(reason="Rebooting for config file update"):
|
||||||
|
#basic = Basic()
|
||||||
|
logger.info("!" * 10 + "REBOOTING DEVICE" + "!"*10)
|
||||||
|
logger.info(reason)
|
||||||
|
r = os.popen("kill -s SIGHUP `cat /var/run/python/supervisord.pid`").read()
|
||||||
|
logger.info(f"REBOOT : {r}")
|
||||||
|
|
||||||
|
def checkFileExist(filename):
|
||||||
|
path = "/var/user/files"
|
||||||
|
if not os.path.exists(path):
|
||||||
|
logger.debug("no folder making files folder in var/user")
|
||||||
|
os.makedirs(path)
|
||||||
|
with open(path + "/" + filename, "a") as f:
|
||||||
|
json.dump({}, f)
|
||||||
|
if not os.path.exists(path + "/" + filename):
|
||||||
|
logger.debug("no creds file making creds file")
|
||||||
|
with open(path + "/" + filename, "a") as f:
|
||||||
|
json.dump({}, f)
|
||||||
|
|
||||||
|
def convertDStoJSON(ds):
|
||||||
|
j = dict()
|
||||||
|
for x in ds:
|
||||||
|
j[x["key"]] = x["value"]
|
||||||
|
return j
|
||||||
|
|
||||||
|
def convertJSONtoDS(j):
|
||||||
|
d = []
|
||||||
|
for key in j.keys():
|
||||||
|
d.append({"key": key, "value": j[key]})
|
||||||
|
return d
|
||||||
|
|
||||||
|
def checkCredentialConfig():
|
||||||
|
logger.debug("CHECKING CONFIG")
|
||||||
|
cfgpath = "/var/user/cfg/device_supervisor/device_supervisor.cfg"
|
||||||
|
credspath = "/var/user/files/creds.json"
|
||||||
|
cfg = dict()
|
||||||
|
with open(cfgpath, "r") as f:
|
||||||
|
cfg = json.load(f)
|
||||||
|
clouds = cfg.get("clouds")
|
||||||
|
logger.debug(clouds)
|
||||||
|
#if not configured then try to configure from stored values
|
||||||
|
if clouds[0]["args"]["clientId"] == "unknown" or clouds[0]["args"]["username"] == "unknown" or not clouds[0]["args"]["passwd"] or clouds[0]["args"]["passwd"] == "unknown":
|
||||||
|
checkFileExist("creds.json")
|
||||||
|
with open(credspath, "r") as c:
|
||||||
|
creds = json.load(c)
|
||||||
|
if creds:
|
||||||
|
logger.debug("updating config with stored data")
|
||||||
|
clouds[0]["args"]["clientId"] = creds["clientId"]
|
||||||
|
clouds[0]["args"]["username"] = creds["userName"]
|
||||||
|
clouds[0]["args"]["passwd"] = creds["password"]
|
||||||
|
cfg["clouds"] = clouds
|
||||||
|
cfg = checkParameterConfig(cfg)
|
||||||
|
with open(cfgpath, "w", encoding='utf-8') as n:
|
||||||
|
json.dump(cfg, n, indent=1, ensure_ascii=False)
|
||||||
|
reboot()
|
||||||
|
else:
|
||||||
|
#assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data
|
||||||
|
checkFileExist("creds.json")
|
||||||
|
with open(credspath, "r") as c:
|
||||||
|
logger.debug("updating stored file with new data")
|
||||||
|
cfg = checkParameterConfig(cfg)
|
||||||
|
with open(cfgpath, "w", encoding='utf-8') as n:
|
||||||
|
json.dump(cfg, n, indent=1, ensure_ascii=False)
|
||||||
|
creds = json.load(c)
|
||||||
|
if creds:
|
||||||
|
if creds["clientId"] != clouds[0]["args"]["clientId"]:
|
||||||
|
creds["clientId"] = clouds[0]["args"]["clientId"]
|
||||||
|
if creds["userName"] != clouds[0]["args"]["username"]:
|
||||||
|
creds["userName"] = clouds[0]["args"]["username"]
|
||||||
|
if creds["password"] != clouds[0]["args"]["passwd"]:
|
||||||
|
creds["password"] = clouds[0]["args"]["passwd"]
|
||||||
|
else:
|
||||||
|
creds["clientId"] = clouds[0]["args"]["clientId"]
|
||||||
|
creds["userName"] = clouds[0]["args"]["username"]
|
||||||
|
creds["password"] = clouds[0]["args"]["passwd"]
|
||||||
|
with open(credspath, "w") as cw:
|
||||||
|
json.dump(creds,cw)
|
||||||
|
|
||||||
|
def checkParameterConfig(cfg):
|
||||||
|
logger.debug("Checking Parameters!!!!")
|
||||||
|
paramspath = "/var/user/files/params.json"
|
||||||
|
cfgparams = convertDStoJSON(cfg.get("labels"))
|
||||||
|
#check stored values
|
||||||
|
checkFileExist("params.json")
|
||||||
|
with open(paramspath, "r") as f:
|
||||||
|
logger.debug("Opened param storage file")
|
||||||
|
params = json.load(f)
|
||||||
|
if params:
|
||||||
|
if cfgparams != params:
|
||||||
|
#go through each param
|
||||||
|
#if not "unknown" and cfg and params aren't the same take from cfg likely updated manually
|
||||||
|
#if key in cfg but not in params copy to params
|
||||||
|
logger.debug("equalizing params between cfg and stored")
|
||||||
|
for key in cfgparams.keys():
|
||||||
|
try:
|
||||||
|
if cfgparams[key] != params[key] and cfgparams[key] != "unknown":
|
||||||
|
params[key] = cfgparams[key]
|
||||||
|
except:
|
||||||
|
params[key] = cfgparams[key]
|
||||||
|
cfg["labels"] = convertJSONtoDS(params)
|
||||||
|
_set_global_args(convertJSONtoDS(params))
|
||||||
|
with open(paramspath, "w") as p:
|
||||||
|
json.dump(params, p)
|
||||||
|
else:
|
||||||
|
with open(paramspath, "w") as p:
|
||||||
|
logger.debug("initializing param file with params in memory")
|
||||||
|
json.dump(convertDStoJSON(get_params()), p)
|
||||||
|
cfg["labels"] = get_params()
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
def sendData(message):
|
||||||
|
#logger.debug(message)
|
||||||
|
try:
|
||||||
|
checkCredentialConfig()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
payload = {"ts": (round(dt.timestamp(dt.now())/600)*600)*1000, "values": {}}
|
||||||
|
for measure in message["measures"]:
|
||||||
|
try:
|
||||||
|
logger.debug(measure)
|
||||||
|
if abs(payload["ts"]/1000 - measure["timestamp"]) > 3600:
|
||||||
|
reboot(reason="Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}".format(payload["ts"]/1000,measure["timestamp"]))
|
||||||
|
if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]:
|
||||||
|
logger.debug("Converting DINT/BOOL to STRING")
|
||||||
|
value = convert_int(measure["name"], measure["value"])
|
||||||
|
logger.debug("Converted {} to {}".format(measure["value"], value))
|
||||||
|
payload["values"][measure["name"]] = value
|
||||||
|
payload["values"][measure["name"] + "_int"] = measure["value"]
|
||||||
|
else:
|
||||||
|
payload["values"][measure["name"]] = measure["value"]
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
|
||||||
|
publish(__topic__, json.dumps(payload), __qos__)
|
||||||
|
publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__)
|
||||||
|
|
||||||
|
def convert_int(plc_tag, value):
|
||||||
|
well_status_codes = {
|
||||||
|
0: "Running",
|
||||||
|
1: "Pumped Off",
|
||||||
|
2: "Alarmed",
|
||||||
|
3: "Locked Out",
|
||||||
|
4: "Stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_control_codes = {
|
||||||
|
0: "Flow",
|
||||||
|
1: "Fluid Level",
|
||||||
|
2: "Tubing Pressure",
|
||||||
|
3: "Manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
downhole_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Connecting",
|
||||||
|
2: "Open Circuit",
|
||||||
|
3: "Shorted",
|
||||||
|
4: "Cannot Decode"
|
||||||
|
}
|
||||||
|
|
||||||
|
permissive_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Flow",
|
||||||
|
2: "Intake Pressure",
|
||||||
|
3: "Intake Temperature",
|
||||||
|
4: "Tubing Pressure",
|
||||||
|
5: "VFD",
|
||||||
|
6: "Fluid Level",
|
||||||
|
7: "Min. Downtime"
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Alarm"
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_vfd_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Locked Out"
|
||||||
|
}
|
||||||
|
|
||||||
|
vfd_fault_codes = {
|
||||||
|
0: "No Fault",
|
||||||
|
2: "Auxiliary Input",
|
||||||
|
3: "Power Loss",
|
||||||
|
4: "UnderVoltage",
|
||||||
|
5: "OverVoltage",
|
||||||
|
7: "Motor Overload",
|
||||||
|
8: "Heatsink OverTemp",
|
||||||
|
9: "Thermister OverTemp",
|
||||||
|
10: "Dynamic Brake OverTemp",
|
||||||
|
12: "Hardware OverCurrent",
|
||||||
|
13: "Ground Fault",
|
||||||
|
14: "Ground Warning",
|
||||||
|
15: "Load Loss",
|
||||||
|
17: "Input Phase Loss",
|
||||||
|
18: "Motor PTC Trip",
|
||||||
|
19: "Task Overrun",
|
||||||
|
20: "Torque Prove Speed Band",
|
||||||
|
21: "Output Phase Loss",
|
||||||
|
24: "Decel Inhibit",
|
||||||
|
25: "OverSpeed Limit",
|
||||||
|
26: "Brake Slipped",
|
||||||
|
27: "Torque Prove Conflict",
|
||||||
|
28: "TP Encls Confict",
|
||||||
|
29: "Analog In Loss",
|
||||||
|
33: "Auto Restarts Exhausted",
|
||||||
|
35: "IPM OverCurrent",
|
||||||
|
36: "SW OverCurrent",
|
||||||
|
38: "Phase U to Ground",
|
||||||
|
39: "Phase V to Ground",
|
||||||
|
40: "Phase W to Ground",
|
||||||
|
41: "Phase UV Short",
|
||||||
|
42: "Phase VW Short",
|
||||||
|
43: "Phase WU Short",
|
||||||
|
44: "Phase UNeg to Ground",
|
||||||
|
45: "Phase VNeg to Ground",
|
||||||
|
46: "Phase WNeg to Ground",
|
||||||
|
48: "System Defaulted",
|
||||||
|
49: "Drive Powerup",
|
||||||
|
51: "Clear Fault Queue",
|
||||||
|
55: "Control Board Overtemp",
|
||||||
|
59: "Invalid Code",
|
||||||
|
61: "Shear Pin 1",
|
||||||
|
62: "Shear Pin 2",
|
||||||
|
64: "Drive Overload",
|
||||||
|
66: "OW Torque Level",
|
||||||
|
67: "Pump Off",
|
||||||
|
71: "Port 1 Adapter",
|
||||||
|
72: "Port 2 Adapter",
|
||||||
|
73: "Port 3 Adapter",
|
||||||
|
74: "Port 4 Adapter",
|
||||||
|
75: "Port 5 Adapter",
|
||||||
|
76: "Port 6 Adapter",
|
||||||
|
77: "IR Volts Range",
|
||||||
|
78: "FluxAmps Ref Range",
|
||||||
|
79: "Excessive Load",
|
||||||
|
80: "AutoTune Aborted",
|
||||||
|
81: "Port 1 DPI Loss",
|
||||||
|
82: "Port 2 DPI Loss",
|
||||||
|
83: "Port 3 DPI Loss",
|
||||||
|
84: "Port 4 DPI Loss",
|
||||||
|
85: "Port 5 DPI Loss",
|
||||||
|
86: "Port 6 DPI Loss",
|
||||||
|
87: "IXo Voltage Range",
|
||||||
|
91: "Primary Velocity Feedback Loss",
|
||||||
|
93: "Hardware Enable Check",
|
||||||
|
94: "Alternate Velocity Feedback Loss",
|
||||||
|
95: "Auxiliary Velocity Feedback Loss",
|
||||||
|
96: "Position Feedback Loss",
|
||||||
|
97: "Auto Tach Switch",
|
||||||
|
100: "Parameter Checksum",
|
||||||
|
101: "Power Down NVS Blank",
|
||||||
|
102: "NVS Not Blank",
|
||||||
|
103: "Power Down NVS Incompatible",
|
||||||
|
104: "Power Board Checksum",
|
||||||
|
106: "Incompat MCB-PB",
|
||||||
|
107: "Replaced MCB-PB",
|
||||||
|
108: "Analog Calibration Checksum",
|
||||||
|
110: "Invalid Power Board Data",
|
||||||
|
111: "Power Board Invalid ID",
|
||||||
|
112: "Power Board App Min Version",
|
||||||
|
113: "Tracking DataError",
|
||||||
|
115: "Power Down Table Full",
|
||||||
|
116: "Power Down Entry Too Large",
|
||||||
|
117: "Power Down Data Checksum",
|
||||||
|
118: "Power Board Power Down Checksum",
|
||||||
|
124: "App ID Changed",
|
||||||
|
125: "Using Backup App",
|
||||||
|
134: "Start on Power Up",
|
||||||
|
137: "External Precharge Error",
|
||||||
|
138: "Precharge Open",
|
||||||
|
141: "Autotune Enc Angle",
|
||||||
|
142: "Autotune Speed Restricted",
|
||||||
|
143: "Autotune Current Regulator",
|
||||||
|
144: "Autotune Inertia",
|
||||||
|
145: "Autotune Travel",
|
||||||
|
13035: "Net IO Timeout",
|
||||||
|
13037: "Net IO Timeout"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
plc_tags = {
|
||||||
|
"wellstatus": well_status_codes.get(value, "Invalid Code"),
|
||||||
|
"pidcontrolmode": pid_control_codes.get(value, "Invalid Code"),
|
||||||
|
"downholesensorstatus": downhole_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmflowrate": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmintakepressure": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmintaketemperature": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmtubingpressure": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmvfd": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmlockout": alarm_vfd_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmfluidlevel": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"runpermissive": permissive_codes.get(value, "Invalid Code"),
|
||||||
|
"startpermissive": permissive_codes.get(value, "Invalid Code"),
|
||||||
|
"last_vfd_fault_code": vfd_fault_codes.get(value, "Invalid Code"),
|
||||||
|
"vfd_fault": vfd_fault_codes.get(value, "Invalid Code"),
|
||||||
|
"flowmeter_fault": alarm_codes.get(value, "Invalid Code")
|
||||||
|
}
|
||||||
|
|
||||||
|
return plc_tags.get(plc_tag, "Invalid Tag")
|
||||||
|
|
||||||
|
|
||||||
29
Pub_Sub/advvfdipp_sru/thingsboard/v2/pub/sendToPLC.py
Normal file
29
Pub_Sub/advvfdipp_sru/thingsboard/v2/pub/sendToPLC.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Enter your python code.
|
||||||
|
import json, time
|
||||||
|
from quickfaas.measure import recall, write
|
||||||
|
from quickfaas.remotebus import publish
|
||||||
|
from common.Logger import logger
|
||||||
|
|
||||||
|
|
||||||
|
def writeplctag(value):
|
||||||
|
#value in the form {"measurement": <measurement_name>, "value": <value to write>}
|
||||||
|
try:
|
||||||
|
#value = json.loads(value.replace("'",'"'))
|
||||||
|
logger.debug(value)
|
||||||
|
#payload format: [{"name": "advvfdipp", "measures": [{"name": "manualfrequencysetpoint", "value": 49}]}]
|
||||||
|
message = [{"name": "advvfdipp", "measures":[{"name":value["measurement"], "value": value["value"]}]}]
|
||||||
|
resp = write(message)
|
||||||
|
logger.debug("RETURN FROM WRITE: {}".format(resp))
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def sendToPLC(message):
|
||||||
|
logger.debug(message)
|
||||||
|
for measure in message["measures"]:
|
||||||
|
logger.debug(measure)
|
||||||
|
#{'ctrlName': 'modbus_converter', 'name': 'SRU_Data[1]', 'health': 1, 'timestamp': 1664894200, 'value': 47}
|
||||||
|
writeplctag({"measurement": measure["name"], "value": measure["value"]})
|
||||||
|
#time.sleep(2)
|
||||||
|
|
||||||
266
Pub_Sub/advvfdipp_sru/thingsboard/v2/sub/receiveCommand.py
Normal file
266
Pub_Sub/advvfdipp_sru/thingsboard/v2/sub/receiveCommand.py
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
import json, time
|
||||||
|
from quickfaas.measure import recall, write
|
||||||
|
from quickfaas.remotebus import publish
|
||||||
|
from common.Logger import logger
|
||||||
|
|
||||||
|
def sync():
|
||||||
|
#get new values and send
|
||||||
|
payload = {}
|
||||||
|
topic = "v1/devices/me/telemetry"
|
||||||
|
try:
|
||||||
|
data = recall()#json.loads(recall().decode("utf-8"))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
logger.debug(data)
|
||||||
|
for controller in data:
|
||||||
|
for measure in controller["measures"]:
|
||||||
|
#publish measure
|
||||||
|
if measure["name"] in ["wellstatus","pidcontrolmode","downholesensorstatus","alarmflowrate","alarmintakepressure","alarmintaketemperature","alarmtubingpressure","alarmvfd","alarmlockout","alarmfluidlevel","runpermissive","startpermissive","last_vfd_fault_code","vfd_fault", "flowmeter_fault"]:
|
||||||
|
payload[measure["name"]] = convert_int(measure["name"], measure["value"])
|
||||||
|
payload[measure["name"]+ "_int"] = measure["value"]
|
||||||
|
else:
|
||||||
|
payload[measure["name"]] = measure["value"]
|
||||||
|
logger.debug("Sending on topic: {}".format(topic))
|
||||||
|
logger.debug("Sending value: {}".format(payload))
|
||||||
|
publish(topic, json.dumps(payload), 1)
|
||||||
|
def writeplctag(value):
|
||||||
|
#value in the form {"measurement": <measurement_name>, "value": <value to write>}
|
||||||
|
try:
|
||||||
|
#value = json.loads(value.replace("'",'"'))
|
||||||
|
logger.debug(value)
|
||||||
|
#payload format: [{"name": "advvfdipp", "measures": [{"name": "manualfrequencysetpoint", "value": 49}]}]
|
||||||
|
message = [{"name": "advvfdipp", "measures":[{"name":value["measurement"], "value": value["value"]}]}]
|
||||||
|
resp = write(message)
|
||||||
|
logger.debug("RETURN FROM WRITE: {}".format(resp))
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def receiveCommand(topic, payload):
|
||||||
|
try:
|
||||||
|
logger.debug(topic)
|
||||||
|
logger.debug(json.loads(payload))
|
||||||
|
p = json.loads(payload)
|
||||||
|
command = p["method"]
|
||||||
|
commands = {
|
||||||
|
"sync": sync,
|
||||||
|
"writeplctag": writeplctag,
|
||||||
|
}
|
||||||
|
if command == "setPLCTag":
|
||||||
|
try:
|
||||||
|
result = commands["writeplctag"](p["params"])
|
||||||
|
logger.debug(result)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
elif command == "changeSetpoint":
|
||||||
|
try:
|
||||||
|
logger.debug("attempting controlpoint write")
|
||||||
|
params_type = {"measurement": "pidcontrolmode", "value": p["params"]["setpointType"]}
|
||||||
|
if params_type["value"]:
|
||||||
|
commands["writeplctag"](params_type)
|
||||||
|
time.sleep(2)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("DID NOT WRITE CONTROL MODE")
|
||||||
|
logger.error(e)
|
||||||
|
try:
|
||||||
|
logger.debug("attempting setpoint write")
|
||||||
|
modes = {0: "flowsetpoint", 1: "fluidlevelsetpoint", 2: "tubingpressuresetpoint", 3: "manualfrequencysetpoint"}
|
||||||
|
params_value = {"value": p["params"]["setpointValue"]}
|
||||||
|
if params_value["value"]:
|
||||||
|
params_value["measurement"] = modes[getMode()]
|
||||||
|
result = commands["writeplctag"](params_value)
|
||||||
|
logger.debug(result)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("DID NOT WRITE SETPOINT")
|
||||||
|
logger.error(e)
|
||||||
|
#logger.debug(command)
|
||||||
|
ack(topic.split("/")[-1])
|
||||||
|
time.sleep(5)
|
||||||
|
sync()
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(e)
|
||||||
|
|
||||||
|
|
||||||
|
def ack(msgid):
|
||||||
|
#logger.debug(msgid)
|
||||||
|
#logger.debug(mac)
|
||||||
|
#logger.debug(name)
|
||||||
|
#logger.debug(value)
|
||||||
|
publish("v1/devices/me/rpc/response/" + str(msgid), json.dumps({"msg": {"time": time.time()}, "metadata": "", "msgType": ""}), 1)
|
||||||
|
|
||||||
|
def getMode():
|
||||||
|
try:
|
||||||
|
data = recall()
|
||||||
|
for controller in data:
|
||||||
|
for measure in controller["measures"]:
|
||||||
|
if measure["name"] == "pidcontrolmode":
|
||||||
|
return measure["value"]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def convert_int(plc_tag, value):
|
||||||
|
well_status_codes = {
|
||||||
|
0: "Running",
|
||||||
|
1: "Pumped Off",
|
||||||
|
2: "Alarmed",
|
||||||
|
3: "Locked Out",
|
||||||
|
4: "Stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_control_codes = {
|
||||||
|
0: "Flow",
|
||||||
|
1: "Fluid Level",
|
||||||
|
2: "Tubing Pressure",
|
||||||
|
3: "Manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
downhole_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Connecting",
|
||||||
|
2: "Open Circuit",
|
||||||
|
3: "Shorted",
|
||||||
|
4: "Cannot Decode"
|
||||||
|
}
|
||||||
|
|
||||||
|
permissive_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Flow",
|
||||||
|
2: "Intake Pressure",
|
||||||
|
3: "Intake Temperature",
|
||||||
|
4: "Tubing Pressure",
|
||||||
|
5: "VFD",
|
||||||
|
6: "Fluid Level",
|
||||||
|
7: "Min. Downtime"
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Alarm"
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_vfd_codes = {
|
||||||
|
0: "OK",
|
||||||
|
1: "Locked Out"
|
||||||
|
}
|
||||||
|
|
||||||
|
vfd_fault_codes = {
|
||||||
|
0: "No Fault",
|
||||||
|
2: "Auxiliary Input",
|
||||||
|
3: "Power Loss",
|
||||||
|
4: "UnderVoltage",
|
||||||
|
5: "OverVoltage",
|
||||||
|
7: "Motor Overload",
|
||||||
|
8: "Heatsink OverTemp",
|
||||||
|
9: "Thermister OverTemp",
|
||||||
|
10: "Dynamic Brake OverTemp",
|
||||||
|
12: "Hardware OverCurrent",
|
||||||
|
13: "Ground Fault",
|
||||||
|
14: "Ground Warning",
|
||||||
|
15: "Load Loss",
|
||||||
|
17: "Input Phase Loss",
|
||||||
|
18: "Motor PTC Trip",
|
||||||
|
19: "Task Overrun",
|
||||||
|
20: "Torque Prove Speed Band",
|
||||||
|
21: "Output Phase Loss",
|
||||||
|
24: "Decel Inhibit",
|
||||||
|
25: "OverSpeed Limit",
|
||||||
|
26: "Brake Slipped",
|
||||||
|
27: "Torque Prove Conflict",
|
||||||
|
28: "TP Encls Confict",
|
||||||
|
29: "Analog In Loss",
|
||||||
|
33: "Auto Restarts Exhausted",
|
||||||
|
35: "IPM OverCurrent",
|
||||||
|
36: "SW OverCurrent",
|
||||||
|
38: "Phase U to Ground",
|
||||||
|
39: "Phase V to Ground",
|
||||||
|
40: "Phase W to Ground",
|
||||||
|
41: "Phase UV Short",
|
||||||
|
42: "Phase VW Short",
|
||||||
|
43: "Phase WU Short",
|
||||||
|
44: "Phase UNeg to Ground",
|
||||||
|
45: "Phase VNeg to Ground",
|
||||||
|
46: "Phase WNeg to Ground",
|
||||||
|
48: "System Defaulted",
|
||||||
|
49: "Drive Powerup",
|
||||||
|
51: "Clear Fault Queue",
|
||||||
|
55: "Control Board Overtemp",
|
||||||
|
59: "Invalid Code",
|
||||||
|
61: "Shear Pin 1",
|
||||||
|
62: "Shear Pin 2",
|
||||||
|
64: "Drive Overload",
|
||||||
|
66: "OW Torque Level",
|
||||||
|
67: "Pump Off",
|
||||||
|
71: "Port 1 Adapter",
|
||||||
|
72: "Port 2 Adapter",
|
||||||
|
73: "Port 3 Adapter",
|
||||||
|
74: "Port 4 Adapter",
|
||||||
|
75: "Port 5 Adapter",
|
||||||
|
76: "Port 6 Adapter",
|
||||||
|
77: "IR Volts Range",
|
||||||
|
78: "FluxAmps Ref Range",
|
||||||
|
79: "Excessive Load",
|
||||||
|
80: "AutoTune Aborted",
|
||||||
|
81: "Port 1 DPI Loss",
|
||||||
|
82: "Port 2 DPI Loss",
|
||||||
|
83: "Port 3 DPI Loss",
|
||||||
|
84: "Port 4 DPI Loss",
|
||||||
|
85: "Port 5 DPI Loss",
|
||||||
|
86: "Port 6 DPI Loss",
|
||||||
|
87: "IXo Voltage Range",
|
||||||
|
91: "Primary Velocity Feedback Loss",
|
||||||
|
93: "Hardware Enable Check",
|
||||||
|
94: "Alternate Velocity Feedback Loss",
|
||||||
|
95: "Auxiliary Velocity Feedback Loss",
|
||||||
|
96: "Position Feedback Loss",
|
||||||
|
97: "Auto Tach Switch",
|
||||||
|
100: "Parameter Checksum",
|
||||||
|
101: "Power Down NVS Blank",
|
||||||
|
102: "NVS Not Blank",
|
||||||
|
103: "Power Down NVS Incompatible",
|
||||||
|
104: "Power Board Checksum",
|
||||||
|
106: "Incompat MCB-PB",
|
||||||
|
107: "Replaced MCB-PB",
|
||||||
|
108: "Analog Calibration Checksum",
|
||||||
|
110: "Invalid Power Board Data",
|
||||||
|
111: "Power Board Invalid ID",
|
||||||
|
112: "Power Board App Min Version",
|
||||||
|
113: "Tracking DataError",
|
||||||
|
115: "Power Down Table Full",
|
||||||
|
116: "Power Down Entry Too Large",
|
||||||
|
117: "Power Down Data Checksum",
|
||||||
|
118: "Power Board Power Down Checksum",
|
||||||
|
124: "App ID Changed",
|
||||||
|
125: "Using Backup App",
|
||||||
|
134: "Start on Power Up",
|
||||||
|
137: "External Precharge Error",
|
||||||
|
138: "Precharge Open",
|
||||||
|
141: "Autotune Enc Angle",
|
||||||
|
142: "Autotune Speed Restricted",
|
||||||
|
143: "Autotune Current Regulator",
|
||||||
|
144: "Autotune Inertia",
|
||||||
|
145: "Autotune Travel",
|
||||||
|
13035: "Net IO Timeout",
|
||||||
|
13037: "Net IO Timeout"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
plc_tags = {
|
||||||
|
"wellstatus": well_status_codes.get(value, "Invalid Code"),
|
||||||
|
"pidcontrolmode": pid_control_codes.get(value, "Invalid Code"),
|
||||||
|
"downholesensorstatus": downhole_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmflowrate": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmintakepressure": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmintaketemperature": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmtubingpressure": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmvfd": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmlockout": alarm_vfd_codes.get(value, "Invalid Code"),
|
||||||
|
"alarmfluidlevel": alarm_codes.get(value, "Invalid Code"),
|
||||||
|
"runpermissive": permissive_codes.get(value, "Invalid Code"),
|
||||||
|
"startpermissive": permissive_codes.get(value, "Invalid Code"),
|
||||||
|
"last_vfd_fault_code": vfd_fault_codes.get(value, "Invalid Code"),
|
||||||
|
"vfd_fault": vfd_fault_codes.get(value, "Invalid Code"),
|
||||||
|
"flowmeter_fault": alarm_codes.get(value, "Invalid Code")
|
||||||
|
}
|
||||||
|
|
||||||
|
return plc_tags.get(plc_tag, "Invalid Tag")
|
||||||
@@ -995,6 +995,97 @@
|
|||||||
"desc": "",
|
"desc": "",
|
||||||
"transformType": 0
|
"transformType": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "water_09_level",
|
||||||
|
"ctrlName": "hrtankbattery",
|
||||||
|
"group": "default",
|
||||||
|
"uploadType": "periodic",
|
||||||
|
"dataType": "FLOAT",
|
||||||
|
"addr": "WT_9.Val",
|
||||||
|
"decimal": 2,
|
||||||
|
"readWrite": "ro",
|
||||||
|
"unit": "",
|
||||||
|
"desc": "",
|
||||||
|
"transformType": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "water_09_hihi_alm",
|
||||||
|
"ctrlName": "hrtankbattery",
|
||||||
|
"group": "default",
|
||||||
|
"uploadType": "periodic",
|
||||||
|
"dataType": "BIT",
|
||||||
|
"addr": "WT_9.Alm_HiHi",
|
||||||
|
"bitMap": 0,
|
||||||
|
"readWrite": "ro",
|
||||||
|
"unit": "",
|
||||||
|
"desc": "",
|
||||||
|
"transformType": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "water_09_hi_alm",
|
||||||
|
"ctrlName": "hrtankbattery",
|
||||||
|
"group": "default",
|
||||||
|
"uploadType": "periodic",
|
||||||
|
"dataType": "BIT",
|
||||||
|
"addr": "WT_9.Alm_Hi",
|
||||||
|
"bitMap": 0,
|
||||||
|
"readWrite": "ro",
|
||||||
|
"unit": "",
|
||||||
|
"desc": "",
|
||||||
|
"transformType": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "water_09_tx_alm",
|
||||||
|
"ctrlName": "hrtankbattery",
|
||||||
|
"group": "default",
|
||||||
|
"uploadType": "periodic",
|
||||||
|
"dataType": "BIT",
|
||||||
|
"addr": "WT_9.Alm_Fail",
|
||||||
|
"bitMap": 0,
|
||||||
|
"readWrite": "ro",
|
||||||
|
"unit": "",
|
||||||
|
"desc": "",
|
||||||
|
"transformType": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "water_09_hihi_spt",
|
||||||
|
"ctrlName": "hrtankbattery",
|
||||||
|
"group": "default",
|
||||||
|
"uploadType": "periodic",
|
||||||
|
"dataType": "FLOAT",
|
||||||
|
"addr": "WT_9.PSet_HiHiLim",
|
||||||
|
"decimal": 2,
|
||||||
|
"readWrite": "ro",
|
||||||
|
"unit": "",
|
||||||
|
"desc": "",
|
||||||
|
"transformType": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "water_09_hi_spt",
|
||||||
|
"ctrlName": "hrtankbattery",
|
||||||
|
"group": "default",
|
||||||
|
"uploadType": "periodic",
|
||||||
|
"dataType": "FLOAT",
|
||||||
|
"addr": "WT_9.PSet_HiLim",
|
||||||
|
"decimal": 2,
|
||||||
|
"readWrite": "ro",
|
||||||
|
"unit": "",
|
||||||
|
"desc": "",
|
||||||
|
"transformType": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "water_09_max_height",
|
||||||
|
"ctrlName": "hrtankbattery",
|
||||||
|
"group": "default",
|
||||||
|
"uploadType": "periodic",
|
||||||
|
"dataType": "FLOAT",
|
||||||
|
"addr": "WT_9.Cfg_PVEUMax",
|
||||||
|
"decimal": 2,
|
||||||
|
"readWrite": "ro",
|
||||||
|
"unit": "",
|
||||||
|
"desc": "",
|
||||||
|
"transformType": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "oil_run_tank",
|
"name": "oil_run_tank",
|
||||||
"ctrlName": "hrtankbattery",
|
"ctrlName": "hrtankbattery",
|
||||||
@@ -2742,6 +2833,57 @@
|
|||||||
"content": "Water Tank 8 transmission error",
|
"content": "Water Tank 8 transmission error",
|
||||||
"alarmLable": "default"
|
"alarmLable": "default"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "water_09_hihi_alm",
|
||||||
|
"ctrlName": "hrtankbattery",
|
||||||
|
"measureName": "water_09_hihi_alm",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "Water Tank 9 crossed HiHi threshold",
|
||||||
|
"alarmLable": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "water_09_hi_alm",
|
||||||
|
"ctrlName": "hrtankbattery",
|
||||||
|
"measureName": "water_09_hi_alm",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "Water Tank 9 crossed Hi threshold",
|
||||||
|
"alarmLable": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "water_09_tx_alm",
|
||||||
|
"ctrlName": "hrtankbattery",
|
||||||
|
"measureName": "water_09_tx_alm",
|
||||||
|
"alarmLevel": 5,
|
||||||
|
"cond1": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": "1.0"
|
||||||
|
},
|
||||||
|
"condOp": "none",
|
||||||
|
"cond2": {
|
||||||
|
"op": "eq",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"content": "Water Tank 9 transmission error",
|
||||||
|
"alarmLable": "default"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "oil_01_hihi_alm",
|
"name": "oil_01_hihi_alm",
|
||||||
"ctrlName": "hrtankbattery",
|
"ctrlName": "hrtankbattery",
|
||||||
3739
Pub_Sub/hrtankbattery/thingsboard/v2/hrtankbattery_tb_v2.cfg
Normal file
3739
Pub_Sub/hrtankbattery/thingsboard/v2/hrtankbattery_tb_v2.cfg
Normal file
File diff suppressed because one or more lines are too long
12
Pub_Sub/hrtankbattery/thingsboard/v2/pub/sendAlarms.py
Normal file
12
Pub_Sub/hrtankbattery/thingsboard/v2/pub/sendAlarms.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Enter your python code.
|
||||||
|
import json, time
|
||||||
|
from common.Logger import logger
|
||||||
|
from quickfaas.remotebus import publish
|
||||||
|
|
||||||
|
|
||||||
|
def sendAlarm(message):
|
||||||
|
logger.info(message)
|
||||||
|
payload = {}
|
||||||
|
payload["ts"] = time.time()*1000
|
||||||
|
payload["values"] = {message["measureName"]: message["value"]}
|
||||||
|
publish(__topic__, json.dumps(payload), __qos__)
|
||||||
138
Pub_Sub/hrtankbattery/thingsboard/v2/pub/sendData.py
Normal file
138
Pub_Sub/hrtankbattery/thingsboard/v2/pub/sendData.py
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
# Enter your python code.
|
||||||
|
import json, os
|
||||||
|
from datetime import datetime as dt
|
||||||
|
from common.Logger import logger
|
||||||
|
from quickfaas.remotebus import publish
|
||||||
|
from quickfaas.global_dict import get as get_params
|
||||||
|
from quickfaas.global_dict import _set_global_args
|
||||||
|
|
||||||
|
def reboot(reason="Rebooting for config file update"):
|
||||||
|
#basic = Basic()
|
||||||
|
logger.info("!" * 10 + "REBOOTING DEVICE" + "!"*10)
|
||||||
|
logger.info(reason)
|
||||||
|
r = os.popen("kill -s SIGHUP `cat /var/run/python/supervisord.pid`").read()
|
||||||
|
logger.info(f"REBOOT : {r}")
|
||||||
|
|
||||||
|
def checkFileExist(filename):
|
||||||
|
path = "/var/user/files"
|
||||||
|
if not os.path.exists(path):
|
||||||
|
logger.info("no folder making files folder in var/user")
|
||||||
|
os.makedirs(path)
|
||||||
|
with open(path + "/" + filename, "a") as f:
|
||||||
|
json.dump({}, f)
|
||||||
|
if not os.path.exists(path + "/" + filename):
|
||||||
|
logger.info("no creds file making creds file")
|
||||||
|
with open(path + "/" + filename, "a") as f:
|
||||||
|
json.dump({}, f)
|
||||||
|
|
||||||
|
def convertDStoJSON(ds):
|
||||||
|
j = dict()
|
||||||
|
for x in ds:
|
||||||
|
j[x["key"]] = x["value"]
|
||||||
|
return j
|
||||||
|
|
||||||
|
def convertJSONtoDS(j):
|
||||||
|
d = []
|
||||||
|
for key in j.keys():
|
||||||
|
d.append({"key": key, "value": j[key]})
|
||||||
|
return d
|
||||||
|
|
||||||
|
def checkCredentialConfig():
|
||||||
|
logger.debug("CHECKING CONFIG")
|
||||||
|
cfgpath = "/var/user/cfg/device_supervisor/device_supervisor.cfg"
|
||||||
|
credspath = "/var/user/files/creds.json"
|
||||||
|
cfg = dict()
|
||||||
|
with open(cfgpath, "r") as f:
|
||||||
|
cfg = json.load(f)
|
||||||
|
clouds = cfg.get("clouds")
|
||||||
|
logger.debug(clouds)
|
||||||
|
#if not configured then try to configure from stored values
|
||||||
|
if clouds[0]["args"]["clientId"] == "unknown" or clouds[0]["args"]["username"] == "unknown" or not clouds[0]["args"]["passwd"] or clouds[0]["args"]["passwd"] == "unknown":
|
||||||
|
checkFileExist("creds.json")
|
||||||
|
with open(credspath, "r") as c:
|
||||||
|
creds = json.load(c)
|
||||||
|
if creds:
|
||||||
|
logger.debug("updating config with stored data")
|
||||||
|
clouds[0]["args"]["clientId"] = creds["clientId"]
|
||||||
|
clouds[0]["args"]["username"] = creds["userName"]
|
||||||
|
clouds[0]["args"]["passwd"] = creds["password"]
|
||||||
|
cfg["clouds"] = clouds
|
||||||
|
cfg = checkParameterConfig(cfg)
|
||||||
|
with open(cfgpath, "w", encoding='utf-8') as n:
|
||||||
|
json.dump(cfg, n, indent=1, ensure_ascii=False)
|
||||||
|
reboot()
|
||||||
|
else:
|
||||||
|
#assuming clouds is filled out, if data is different then assume someone typed in something new and store it, if creds is empty fill with clouds' data
|
||||||
|
checkFileExist("creds.json")
|
||||||
|
with open(credspath, "r") as c:
|
||||||
|
logger.debug("updating stored file with new data")
|
||||||
|
cfg = checkParameterConfig(cfg)
|
||||||
|
with open(cfgpath, "w", encoding='utf-8') as n:
|
||||||
|
json.dump(cfg, n, indent=1, ensure_ascii=False)
|
||||||
|
creds = json.load(c)
|
||||||
|
if creds:
|
||||||
|
if creds["clientId"] != clouds[0]["args"]["clientId"]:
|
||||||
|
creds["clientId"] = clouds[0]["args"]["clientId"]
|
||||||
|
if creds["userName"] != clouds[0]["args"]["username"]:
|
||||||
|
creds["userName"] = clouds[0]["args"]["username"]
|
||||||
|
if creds["password"] != clouds[0]["args"]["passwd"]:
|
||||||
|
creds["password"] = clouds[0]["args"]["passwd"]
|
||||||
|
else:
|
||||||
|
creds["clientId"] = clouds[0]["args"]["clientId"]
|
||||||
|
creds["userName"] = clouds[0]["args"]["username"]
|
||||||
|
creds["password"] = clouds[0]["args"]["passwd"]
|
||||||
|
with open(credspath, "w") as cw:
|
||||||
|
json.dump(creds,cw)
|
||||||
|
|
||||||
|
def checkParameterConfig(cfg):
|
||||||
|
logger.debug("Checking Parameters!!!!")
|
||||||
|
paramspath = "/var/user/files/params.json"
|
||||||
|
cfgparams = convertDStoJSON(cfg.get("labels"))
|
||||||
|
#check stored values
|
||||||
|
checkFileExist("params.json")
|
||||||
|
with open(paramspath, "r") as f:
|
||||||
|
logger.debug("Opened param storage file")
|
||||||
|
params = json.load(f)
|
||||||
|
if params:
|
||||||
|
if cfgparams != params:
|
||||||
|
#go through each param
|
||||||
|
#if not "unknown" and cfg and params aren't the same take from cfg likely updated manually
|
||||||
|
#if key in cfg but not in params copy to params
|
||||||
|
logger.debug("equalizing params between cfg and stored")
|
||||||
|
for key in cfgparams.keys():
|
||||||
|
try:
|
||||||
|
if cfgparams[key] != params[key] and cfgparams[key] != "unknown":
|
||||||
|
params[key] = cfgparams[key]
|
||||||
|
except:
|
||||||
|
params[key] = cfgparams[key]
|
||||||
|
cfg["labels"] = convertJSONtoDS(params)
|
||||||
|
_set_global_args(convertJSONtoDS(params))
|
||||||
|
with open(paramspath, "w") as p:
|
||||||
|
json.dump(params, p)
|
||||||
|
else:
|
||||||
|
with open(paramspath, "w") as p:
|
||||||
|
logger.debug("initializing param file with params in memory")
|
||||||
|
json.dump(convertDStoJSON(get_params()), p)
|
||||||
|
cfg["labels"] = get_params()
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
def sendData(message):
|
||||||
|
#logger.debug(message)
|
||||||
|
try:
|
||||||
|
checkCredentialConfig()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
payload = {"ts": (round(dt.timestamp(dt.now())/600)*600)*1000, "values": {}}
|
||||||
|
for measure in message["measures"]:
|
||||||
|
try:
|
||||||
|
logger.debug(measure)
|
||||||
|
if abs(payload["ts"]/1000 - measure["timestamp"]) > 3600:
|
||||||
|
reboot(reason="Poll timestamp and actual timestamp out of sync. Actual: {} Poll: {}".format(payload["ts"]/1000,measure["timestamp"]))
|
||||||
|
payload["values"][measure["name"]] = measure["value"]
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
|
||||||
|
publish(__topic__, json.dumps(payload), __qos__)
|
||||||
|
publish("v1/devices/me/attributes", json.dumps({"latestReportTime": (round(dt.timestamp(dt.now())/600)*600)*1000}), __qos__)
|
||||||
|
|
||||||
66
Pub_Sub/hrtankbattery/thingsboard/v2/sub/receiveCommand.py
Normal file
66
Pub_Sub/hrtankbattery/thingsboard/v2/sub/receiveCommand.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import json, time
|
||||||
|
from quickfaas.measure import recall, write
|
||||||
|
from quickfaas.remotebus import publish
|
||||||
|
from common.Logger import logger
|
||||||
|
|
||||||
|
def sync():
|
||||||
|
#get new values and send
|
||||||
|
payload = {}
|
||||||
|
topic = "v1/devices/me/telemetry"
|
||||||
|
try:
|
||||||
|
data = recall()#json.loads(recall().decode("utf-8"))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
logger.debug(data)
|
||||||
|
for controller in data:
|
||||||
|
for measure in controller["measures"]:
|
||||||
|
#publish measure
|
||||||
|
payload[measure["name"]] = measure["value"]
|
||||||
|
logger.debug("Sending on topic: {}".format(topic))
|
||||||
|
logger.debug("Sending value: {}".format(payload))
|
||||||
|
publish(topic, json.dumps(payload), 1)
|
||||||
|
def writeplctag(value):
|
||||||
|
#value in the form {"measurement": <measurement_name>, "value": <value to write>}
|
||||||
|
try:
|
||||||
|
#value = json.loads(value.replace("'",'"'))
|
||||||
|
logger.debug(value)
|
||||||
|
#payload format: [{"name": "advvfdipp", "measures": [{"name": "manualfrequencysetpoint", "value": 49}]}]
|
||||||
|
message = [{"name": "hrtankbattery", "measures":[{"name":value["measurement"], "value": value["value"]}]}]
|
||||||
|
resp = write(message)
|
||||||
|
logger.debug("RETURN FROM WRITE: {}".format(resp))
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def receiveCommand(topic, payload):
|
||||||
|
try:
|
||||||
|
logger.debug(topic)
|
||||||
|
logger.debug(json.loads(payload))
|
||||||
|
p = json.loads(payload)
|
||||||
|
command = p["method"]
|
||||||
|
commands = {
|
||||||
|
"sync": sync,
|
||||||
|
"writeplctag": writeplctag,
|
||||||
|
}
|
||||||
|
if command == "setPLCTag":
|
||||||
|
try:
|
||||||
|
result = commands["writeplctag"](p["params"])
|
||||||
|
logger.debug(result)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
#logger.debug(command)
|
||||||
|
ack(topic.split("/")[-1])
|
||||||
|
time.sleep(5)
|
||||||
|
sync()
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(e)
|
||||||
|
|
||||||
|
|
||||||
|
def ack(msgid):
|
||||||
|
#logger.debug(msgid)
|
||||||
|
#logger.debug(mac)
|
||||||
|
#logger.debug(name)
|
||||||
|
#logger.debug(value)
|
||||||
|
publish("v1/devices/me/rpc/response/" + str(msgid), json.dumps({"msg": {"time": time.time()}, "metadata": "", "msgType": ""}), 1)
|
||||||
|
|
||||||
Reference in New Issue
Block a user