diff --git a/.DS_Store b/.DS_Store index cbbb4f6..90c1448 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/advvfdipp/.DS_Store b/advvfdipp/.DS_Store index 7f3c5ac..00e2fb6 100644 Binary files a/advvfdipp/.DS_Store and b/advvfdipp/.DS_Store differ diff --git a/advvfdipp/Tags.py b/advvfdipp/Tags.py new file mode 100644 index 0000000..e8954e7 --- /dev/null +++ b/advvfdipp/Tags.py @@ -0,0 +1,50 @@ +from Channel import PLCChannel, ModbusChannel +from advvfdipp import PLC_IP_ADDRESS + +tags = [ + PLCChannel(PLC_IP_ADDRESS, "flowrate","val_Flowmeter","REAL", 300, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "fluidlevel","val_FluidLevel","REAL", 2, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "intakepressure","val_IntakePressure","REAL", 10, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "intaketemperature","val_IntakeTemperature","REAL", 5, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "tubingpressure","val_TubingPressure","REAL", 10, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "pidcontrolmode","sts_PID_Control","BOOL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "wellstatus","Device_Status_INT","INT", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "vfdfrequency","VFD_SpeedFdbk","REAL", 5, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "flowtotal","Flow_Total[0]","REAL", 100, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "energytotal","Energy_Total[0]","REAL", 10, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "vfdcurrent","VFD_OutCurrent","REAL", 5, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "downholesensorstatus","Downhole_Sensor_Status_INT","INT", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "fluidspecificgravity","cfg_FluidSpecificGravity","REAL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "flowtotalyesterday","Flow_Total[1]","REAL", 100, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "energytotalyesterday","Energy_Total[1]","REAL", 10, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "alarmflowrate","alarm_Flowmeter","BOOL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "alarmintakepressure","alarm_IntakePressure","BOOL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "alarmintaketemperature","alarm_IntakeTemperature","BOOL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "alarmtubingpressure","alarm_TubingPressure","BOOL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "alarmvfd","alarm_VFD","BOOL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "alarmlockout","alarm_Lockout","BOOL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "runpermissive","Run_Permissive_INT","INT", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "startpermissive","Start_Permissive_INT","INT", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "startcommand","cmd_Start","BOOL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "stopcommand","cmd_Stop","BOOL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "flowsetpoint","cfg_PID_FlowSP","REAL", 1, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "fluidlevelsetpoint","cfg_PID_FluidLevelSP","REAL", 1, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "manualfrequencysetpoint","cfg_PID_ManualSP","REAL", 1, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "tubingpressuresetpoint","cfg_PID_TubingPressureSP","REAL", 1, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "alarmfluidlevel","alarm_FluidLevel","BOOL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "pressureshutdownlimit","AIn_IntakePressure.Val_LoLim","REAL", 1, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "pressurestartuplimit","AIn_IntakePressure.Val_HiLim","REAL", 1, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "temperatureshutdownlimit","AIn_IntakeTemperature.Val_HiLim","REAL", 1, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "temperaturestartuplimit","AIn_IntakeTemperature.Val_LoLim","REAL", 1, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "sensorheight","cfg_DHSensorDistToIntake","REAL", 1, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "last_vfd_fault_code","PowerFlex755.Val_LastFaultCode","INT", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "vfd_fault","sts_CurrentVFDFaultCode","INT", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "controllerfault_io","ControllerFault_IO","BOOL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "controllerfault_program","ControllerFault_Program","BOOL", 1, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "minvfdfrequency","PowerFlex755.Cfg_MinSpdRef","REAL", 1, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "maxvfdfrequency","PowerFlex755.Cfg_MaxSpdRef","REAL", 1, 86400, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "hartnettotal","in_HART_Flowmeter_Net","REAL", 100, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "hartfwdtotal","in_HART_Flowmeter_Fwd","REAL", 100, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "hartrevtotal","in_HART_Flowmeter_Rev","REAL", 100, 3600, plc_type="CLX"), + PLCChannel(PLC_IP_ADDRESS, "pondvolume","Val_Pond_Volume","REAL", 1000000, 3600, plc_type="CLX") +] \ No newline at end of file diff --git a/advvfdipp/advvfdippv2/advvfdipp.py b/advvfdipp/advvfdippv2/advvfdipp.py index 16dd9f5..23e00d0 100644 --- a/advvfdipp/advvfdippv2/advvfdipp.py +++ b/advvfdipp/advvfdippv2/advvfdipp.py @@ -70,7 +70,7 @@ class start(threading.Thread, deviceBase): mqtt=mqtt, Nodes=Nodes) self.daemon = True - self.version = "18" + self.version = "19" self.finished = threading.Event() self.force_send = False self.public_ip_address = "" @@ -84,6 +84,16 @@ class start(threading.Thread, deviceBase): self.rts.saveDataToFile() self.rts.manageTime() self.today = dt.now().date() + deviceMap = {} + with open("drivers/deviceMap.json", "r") as dm: + deviceMap = json.load(dm) + with open("provision.json", "w+") as creds: + p = { + "deviceName": deviceMap[mac], + "provisionDeviceKey": "lkc7ra5l4dnyp782d3px", + "provisionDeviceSecret": "p6olkitsteiwkf1pv7m5" + } + json.dump(p, creds, indent=4) threading.Thread.start(self) # this is a required function for all drivers, its goal is to upload some piece of data diff --git a/advvfdipp/advvfdippv2/config.txt b/advvfdipp/advvfdippv2/config.txt index 2b79fd7..d9c1d0f 100644 --- a/advvfdipp/advvfdippv2/config.txt +++ b/advvfdipp/advvfdippv2/config.txt @@ -6,10 +6,11 @@ "file6": "persistence.py", "file5": "utilities.py", "file4": "Tags.py", - "file5": "runtimeStats.py" + "file5": "runtimeStats.py", + "file6": "deviceMap.json" }, "deviceName": "advvfdipp", - "releaseVersion": "18", + "releaseVersion": "19", "driverFileName": "advvfdipp.py", "driverId": "0100" } \ No newline at end of file diff --git a/advvfdipp/advvfdippv2/deviceMap.json b/advvfdipp/advvfdippv2/deviceMap.json new file mode 100644 index 0000000..fa7dc7c --- /dev/null +++ b/advvfdipp/advvfdippv2/deviceMap.json @@ -0,0 +1,292 @@ +{ + "c4:93:00:0e:d5:03": "Nail Ranch 37 SR 2-3", + "c4:93:00:0c:68:36": "Wrage 21 SR 2-2", + "c4:93:00:08:d0:11": "Wrage 28 SR 2-2", + "b8:27:eb:46:8d:7d": "Free 40 WS 2-2", + "b8:27:eb:78:03:88": "Wilkinson 1 WS 1-9", + "b8:27:eb:86:b6:dc": "Wilkinson 1 WS 1-10B", + "b8:27:eb:06:b1:94": "Wilkinson 39 WS 1-3", + "b8:27:eb:02:2f:f0": "Wilkinson 4 WS 1-10", + "b8:27:eb:c1:ac:f5": "Horton 34 WS 10-5", + "c4:93:00:0a:89:f5": "Bowling WW 4-1", + "c4:93:00:08:d0:65": "Banay WW 7-1", + "c4:93:00:0e:e9:c1": "Banay WW 5-1", + "c4:93:00:09:51:ce": "Bowling WW 37-1", + "c4:93:00:0c:68:57": "Banay WW 504", + "c4:93:00:0d:f2:68": "Banay WW 18 #4", + "c4:93:00:0d:bb:48": "Banay WW 18 #9", + "00:00:01:00:00:05": "Windham 108-1", + "00:00:01:00:00:07": "Windham 108-3", + "c4:93:00:08:d4:49": "Wrage Ranch 32 SR 1-1", + "b8:27:eb:68:43:70": "LimeQuest 5 WS 10-10", + "00:00:00:00:00:02": "Florence WW #2", + "00:00:00:00:00:03": "Florence WW #1", + "00:00:00:00:00:11": "Madelyn Kate #3 WW", + "00:00:00:00:00:14": "Jessica WW #3", + "00:00:01:00:00:01": "Windham 108-7", + "00:00:01:00:00:02": "Windham 108-6", + "00:00:01:00:00:03": "Windham 108-5", + "00:00:01:00:00:04": "Windham 107-1", + "00:00:01:00:00:08": "Windham 107-2", + "00:00:01:00:00:09": "Windham 108-8", + "00:00:01:00:00:10": "Windham 108-10", + "00:00:01:00:00:11": "Windham 108-2", + "00:00:01:00:00:12": "Windham 108-9", + "00:00:00:00:00:18": "Jessica WW #7", + "c4:93:00:0d:f1:6c": "Faudree Frac Pit Pump #1", + "c4:93:00:0d:f2:8c": "Faudree Frac Pit Pump #2", + "c4:93:00:03:af:34": "Wilkinson Ranch 34 SR 2-2", + "c4:93:00:05:dd:a2": "Nail Ranch 2 SR 3-3", + "c4:93:00:03:54:c5": "Nail Ranch 38 SR 2-3", + "c4:93:00:03:69:c8": "Nail Ranch 25 SR 2-1", + "c4:93:00:05:dd:ed": "Nail Ranch 28 SR 3-3", + "c4:93:00:03:56:7b": "Nail Ranch 38 SR 1-3", + "c4:93:00:03:6b:12": "Nail Ranch 3 SR 3-2", + "c4:93:00:03:7f:b2": "Nail Ranch 28 SR 2-2", + "c4:93:00:05:85:1f": "Nail Ranch 28 SR 1-1", + "c4:93:00:03:6b:2d": "Guitar 22 SR 3-3", + "c4:93:00:0c:d2:29": "Wilkinson Ranch 33 SR 2-2", + "c4:93:00:0c:67:af": "Wilkinson Ranch 35 SR 1-1", + "c4:93:00:0c:aa:75": "Wilkinson Ranch 1 SR 2-2", + "c4:93:00:0d:f3:55": "Limequest Transfer Lite", + "c4:93:00:0d:f2:5c": "S. Wilkinson Transfer Lite", + "c4:93:00:0d:f2:8f": "Nail Ranch 2 SR 2-2", + "c4:93:00:0d:f0:ca": "Horton Transfer Lite", + "c4:93:00:0d:f2:b0": "South Wilkinson Transfer #2", + "b8:27:eb:16:f0:64": "Wilkinson 39 WS 1-5", + "b8:27:eb:d8:64:a6": "Wilkinson 39 WS 1-4", + "b8:27:eb:5a:1c:1e": "Wilkinson 39 WS 1-2", + "b8:27:eb:a0:e9:f9": "Free 40 WS 1-2", + "b8:27:eb:da:8d:ea": "Wilkinson 39 WS 1-1", + "b8:27:eb:9a:2e:f0": "Free 32 WS 3-10C", + "b8:27:eb:06:d1:c0": "Free 40 WS 5-6", + "b8:27:eb:75:d2:6a": "Free 40 WS 1-4", + "b8:27:eb:e0:0b:2c": "Free 40 WS 1-6", + "b8:27:eb:01:75:8e": "Free 32 WS 3-10A", + "b8:27:eb:06:2e:17": "Wilkinson 34 WS 9-10", + "b8:27:eb:6d:7f:6c": "Wilkinson 33 WS 10-3A", + "b8:27:eb:7d:e9:f8": "Wilkinson 33 WS 10-3B", + "b8:27:eb:1c:c4:49": "Wilkinson 33 WS 10-1B", + "b8:27:eb:f9:71:92": "Wilkinson 33 WS 6-7", + "b8:27:eb:d4:cb:e4": "Free 32 WS 3-10B", + "b8:27:eb:0e:6a:13": "LimeQuest 5 WS 9-9", + "b8:27:eb:2b:d6:59": "LimeQuest 5 WS 6-8", + "b8:27:eb:92:a0:18": "LimeQuest 5 WS 2-4", + "b8:27:eb:92:65:df": "LimeQuest 5 WS 8-5", + "b8:27:eb:5c:4e:e4": "LimeQuest 5 WS 7-5", + "b8:27:eb:0e:2e:f2": "LimeQuest 5 WS 4-7", + "b8:27:eb:c4:7e:50": "Horton 23 WS 5-6", + "b8:27:eb:1e:a1:f7": "Horton 23 WS 8-6", + "b8:27:eb:fa:2d:73": "Horton 23 WS 6-6", + "b8:27:eb:bd:3b:55": "Horton 34 WS 1-2", + "b8:27:eb:a7:7f:6f": "Horton 23 WS 5-2", + "b8:27:eb:2f:c5:8c": "Horton 23 WS 5-5", + "b8:27:eb:e9:c5:7d": "Wilkinson 37 WS 1-9B", + "b8:27:eb:96:a0:2d": "Wilkinson 39 WS 2-2", + "c4:93:00:0d:bb:42": "Wilkinson 37 WS 1-8", + "b8:27:eb:b8:9b:a7": "Wilkinson 1 WS 9-4B", + "c4:93:00:0d:bb:45": "ToolBox South", + "c4:93:00:08:cf:c0": "Carmanita WW 12-2", + "c4:93:00:08:cf:ba": "Carmanita WW 12-1", + "c4:93:00:08:cf:0c": "Banay North Frac Pit", + "c4:93:00:08:d4:31": "Banay South Frac Pit", + "c4:93:00:0a:8a:0d": "Banay South Inlet", + "c4:93:00:09:4c:ee": "Banay WW 18 #3", + "c4:93:00:0b:0c:d5": "Carmanita WW 12-3", + "c4:93:00:0c:aa:ff": "Banay WW 8-5", + "c4:93:00:0d:f1:5d": "Banay WW 8-2", + "c4:93:00:0d:e8:9f": "Banay WW 6-1", + "c4:93:00:0d:f1:87": "Banay WW 18 #10", + "c4:93:00:03:7c:dc": "Carmanita WW 12-4", + "c4:93:00:0d:f5:56": "Banay WW 18 #1", + "00:00:00:00:00:04": "Caden WW #1", + "00:00:00:00:00:05": "Caden WW #2", + "00:00:00:00:00:06": "Caden WW #3", + "00:00:00:00:00:07": "Caden WW #4", + "00:00:00:00:00:09": "Lisa WW #1", + "00:00:00:00:00:08": "Caden WW #6", + "00:00:00:00:00:16": "Laurie Gwen WW #1", + "00:00:00:00:00:10": "Jessica WW #4", + "00:00:00:00:00:12": "Jessica WW #1", + "00:00:00:00:00:13": "Jessica WW #2", + "b8:27:eb:a9:df:e5": "Denali East Frac Pit", + "c4:93:00:0d:f1:c0": "Banay WW 8-4", + "00:00:00:00:00:17": "Jessica WW #5", + "c4:93:00:0b:0c:f6": "Map Rock Transfer Pump Monitor", + "b8:27:eb:aa:8a:53": "LimeQuest 5 WS 7-9", + "c4:93:00:09:51:bf": "Banay North Pit Inlet #1", + "c4:93:00:0d:f2:b9": "Banay North Pit Outlet #1", + "c4:93:00:0d:f5:44": "Yvonne Frac Pit", + "b8:27:eb:be:09:91": "Denali Frac Pit", + "b8:27:eb:df:53:70": "Horton 34 WS 1-4", + "00:00:02:00:00:02": "Cindy #1", + "00:00:02:00:00:08": "Cindy #3", + "00:00:02:00:00:11": "Cindy #2", + "00:00:03:00:00:03": "Lindsey #3", + "00:00:02:00:00:09": "Elizabeth 1", + "00:00:02:00:00:13": "Railway 12-3", + "00:00:02:00:00:14": "Railway 12-2", + "00:00:02:00:00:15": "Elizabeth B1", + "00:00:02:00:00:16": "Elizabeth B2", + "00:00:02:00:00:17": "Rhonda 1", + "00:00:02:00:00:18": "Sec 46 #1", + "00:00:02:00:00:19": "Cynthia 1", + "00:00:02:00:00:20": "Nancy #2", + "00:00:02:00:00:21": "Nancy #1", + "00:00:02:00:00:22": "Rhonda Pit", + "00:00:03:00:00:05": "Jitterbug 28-1", + "00:00:03:00:00:06": "Reagan #1", + "00:00:00:00:00:19": "Aurora 7", + "00:00:00:00:00:20": "Aurora 8", + "00:00:00:00:00:21": "Aurora 9", + "00:00:00:00:00:22": "Aurora 10", + "00:00:00:00:00:23": "Aurora 11", + "00:00:00:00:00:24": "Aurora 6", + "00:00:05:00:00:01": "RebJean #2", + "00:00:05:00:00:02": "Terri #6", + "00:00:05:00:00:03": "RobJane #2", + "00:00:05:00:00:04": "RobJane #3", + "00:00:05:00:00:05": "RebJean #1", + "00:00:05:00:00:06": "RobJane #1", + "00:00:05:00:00:07": "Kelsey #2", + "00:00:05:00:00:09": "Stephanie 41 #2", + "00:00:05:00:00:10": "Kelsey #1", + "00:00:05:00:00:11": "Stephanie 41 #3", + "00:00:05:00:00:12": "RobJane #4", + "00:00:05:00:00:16": "Terri #2", + "00:00:05:00:00:15": "Terri #1", + "00:00:05:00:00:14": "Terri #3", + "00:00:05:00:00:13": "Terri #4", + "b8:27:eb:80:2e:f7": "LimeQuest 5 WS 3-5", + "00:00:05:00:00:18": "Mary 43 #3", + "00:00:05:00:00:19": "Mary 43 #5", + "00:00:05:00:00:20": "Mary 43 #2", + "00:00:05:00:00:21": "Mary 43 #1", + "00:00:05:00:00:22": "KD #2", + "00:00:05:00:00:23": "KD #4", + "00:00:05:00:00:24": "KD #7", + "00:00:05:00:00:25": "KD #5", + "00:00:02:00:00:01": "Bobbie #1", + "00:00:02:00:00:03": "Bobbie #2", + "00:00:02:00:00:04": "Elizabeth A1", + "00:00:02:00:00:05": "Patty #1", + "c4:93:00:0d:f2:80": "Free Transfer Pit", + "00:00:02:00:00:06": "Rhonda 2", + "b8:27:eb:10:f5:1c": "Wilkinson 34 WS 5-10", + "b8:27:eb:c6:4d:a1": "Wilkinson 33 WS 5-2", + "b8:27:eb:fc:49:51": "Wilkinson 33 WS 6-3", + "b8:27:eb:1c:72:30": "Wilkinson 37 WS 7-8", + "b8:27:eb:ce:5d:4c": "Wilkinson 33 WS 4-1", + "b8:27:eb:b8:e9:52": "Wilkinson 37 WS 8-8", + "b8:27:eb:d8:b8:b6": "Wilkinson 34 WS 1-8", + "b8:27:eb:4f:f2:44": "Wilkinson 39 WS 2-4", + "00:00:00:00:00:25": "Trumann 1", + "00:00:00:00:00:26": "Trumann 3", + "00:00:00:00:00:27": "Trumann 4", + "00:00:00:00:00:28": "Trumann 5", + "00:00:00:00:00:29": "Trumann 2", + "00:00:02:00:00:07": "Patty #2", + "b8:27:eb:a6:a8:9a": "Wilkinson 37 WS 10-9", + "b8:27:eb:e4:44:da": "Wilkinson 33 WS 3-1", + "b8:27:eb:e0:0b:44": "Wilkinson 34 WS 2-10", + "b8:27:eb:8c:68:2a": "Wilkinson 37 WS 1-5", + "b8:27:eb:9b:fe:97": "Wilkinson 37 WS 3-5", + "b8:27:eb:0e:b3:e2": "Wilkinson 37 WS 3-6", + "b8:27:eb:d6:93:8b": "Wilkinson 37 WS 5-7", + "00:00:01:00:00:14": "Kate A1", + "00:00:01:00:00:15": "Kate A2", + "00:00:01:00:00:16": "Kate B1", + "00:00:01:00:00:17": "Tessa Lyn", + "00:00:02:00:00:10": "Patty #3", + "00:00:05:00:00:26": "Smith #1", + "00:00:05:00:00:27": "Smith #2", + "00:00:05:00:00:28": "Dorcus", + "00:00:06:00:00:01": "Monique #1", + "00:00:06:00:00:02": "Monique #2", + "00:00:06:00:00:03": "Monique #3", + "00:00:06:00:00:04": "Dawn #2", + "00:00:06:00:00:05": "Dawn #3", + "00:00:02:00:00:24": "Yvonne Transfer Pump 3", + "00:00:02:00:00:25": "Yvonne Transfer Pump 2", + "00:00:02:00:00:26": "Yvonne Transfer Pump 1", + "00:00:02:00:00:27": "Bobbie #3", + "00:00:05:00:00:29": "Kelsey Pit", + "b8:27:eb:83:24:8c": "Wilkinson 34 WS 10-9", + "c4:93:00:0d:f0:01": "Banay WW 18 #5", + "b8:27:eb:e5:59:03": "Wilkinson 39 WS 1-10", + "b8:27:eb:c8:1c:07": "Wilkinson 37 WS 4-7", + "c4:93:00:0d:ef:fb": "Banay WW 5-2", + "c4:93:00:0d:e8:69": "Banay WW 8-3", + "c4:93:00:0d:ef:53": "Banay WW 18 #7", + "c4:93:00:0d:f0:0d": "Banay WW 806 North", + "c4:93:00:0d:e8:75": "Banay WW 806 South", + "00:00:07:00:00:01": "Banay WW 18 #8", + "c4:93:00:0d:f3:73": "Denali East Inlet", + "b8:27:eb:18:05:d6": "Wilkinson 39 WS 2-8", + "c4:93:00:0d:f1:36": "Wilkinson Ranch 39 SR 1-1", + "c4:93:00:0d:e0:ef": "Wilkinson 37 WS 1-7", + "b8:27:eb:62:ed:99": "LimeQuest 5 WS 8-9", + "b8:27:eb:ca:94:0f": "LimeQuest 5 WS 1-4", + "b8:27:eb:47:eb:ae": "LimeQuest 10 WS 3-6", + "c4:93:00:0b:0c:c9": "Wrage 33 SR 3-3", + "c4:93:00:0d:f1:a8": "N. Wilkinson Transfer Lite", + "b8:27:eb:c6:e5:b3": "Wilkinson 33 WS 10-4", + "b8:27:eb:a9:be:d4": "Wilkinson 34 WS 9-9", + "00:00:03:00:00:01": "Lindsey #1", + "00:00:03:00:00:02": "Lindsey #2", + "b8:27:eb:95:68:93": "Wilkinson 1 WS 2-10", + "b8:27:eb:56:42:2b": "Wilkinson 33 ws 10-1A", + "c4:93:00:0d:f2:89": "Denali East Transfer Pump Monitor", + "c4:93:00:08:c6:81": "Map Rock Transfer Pump Monitor #2", + "b8:27:eb:47:6b:9d": "Wilkinson 37 WS 1-10", + "b8:27:eb:51:cc:bc": "Wilkinson 1 WS 1-10A", + "b8:27:eb:eb:6a:81": "Horton 34 WS 1-3", + "b8:27:eb:19:83:ab": "Wilkinson 39 ws 3-8", + "b8:27:eb:5e:49:a6": "Wilkinson 34 WS 6-10", + "b8:27:eb:6e:7b:1b": "Free 40 SR 2-1", + "c4:93:00:08:d4:13": "Nail Ranch 12 SR 1-3", + "b8:27:eb:5d:dd:09": "Wilkinson 33 WS 6-2", + "b8:27:eb:fd:a2:43": "Wilkinson 39 WS 1-7", + "b8:27:eb:d1:bc:61": "Wilkinson 2 WS 2-9", + "c4:93:00:0d:e9:41": "Dawn Frac Pit", + "b8:27:eb:8a:a9:65": "Wilkinson 34 WS 10-10", + "b8:27:eb:a8:41:f0": "Wilkinson 39 WS 2-10", + "b8:27:eb:7c:d7:c5": "Free 40 WS 1-1", + "00:00:00:00:00:01": "Barnett 19-2 WW", + "00:00:00:00:00:31": "Barnett 24-1", + "b8:27:eb:42:c3:4c": "Wilkinson 39 WS 1-6", + "c4:93:00:08:cf:18": "ToolBox North", + "b8:27:eb:50:ee:26": "Wilkinson 33 WS 10-2", + "c4:93:00:0b:0c:de": "Nail Ranch 37 SR 3-2", + "b8:27:eb:28:f9:49": "Wilkinson 37 WS 8-6", + "00:00:02:00:00:28": "Nancy Pit", + "c4:93:00:0d:e9:53": "Banay WW 18 #2", + "c4:93:00:0d:ef:26": "Banay WW 18 #6", + "c4:93:00:0d:f1:c6": "Banay WW 6-2", + "c4:93:00:0d:e9:3e": "Banay WW #7", + "00:18:05:1e:ae:b8": "Banay WW 7-2", + "00:18:05:1f:8d:0b": "Penny North", + "00:18:05:1f:8d:0e": "Penny South", + "b8:27:eb:96:3c:23": "Wilkinson 37 WS 5-5", + "c4:93:00:06:71:aa": "LLL 6 SR 1-1", + "b8:27:eb:48:aa:63": "Wilkinson 39 WS 1-9", + "b8:27:eb:40:0e:b2": "Wilkinson 39 WS 1-8", + "b8:27:eb:2d:86:50": "Wilkinson 39 WS 2-6", + "b8:27:eb:01:6c:fc": "LimeQuest 5 WS 10-9", + "b8:27:eb:28:e1:d6": "Baylee Pit", + "00:00:06:00:00:06": "Dawn to Terri", + "c4:93:00:0e:e9:ee": "Baylee Pit Transfer", + "00:00:05:00:00:31": "TM1", + "00:00:05:00:00:30": "TM2", + "00:00:05:00:00:32": "WC41-1", + "00:00:05:00:00:33": "WC41-2", + "00:00:05:00:00:34": "WC41-3", + "00:00:00:00:00:33": "Jordan Pit Pump#1", + "00:00:00:00:00:34": "Jordan Pit Pump #2", + "00:00:00:00:00:35": "Jessica #6", + "c4:93:00:0d:f2:41": "Jones A", + "00:00:01:00:00:23": "Kelly #1", + "00:00:01:00:00:24": "Kelly #2", + "00:00:01:00:00:25": "Kelly #3", + "02:42:ac:11:00:04": "RPi Test Device" +} \ No newline at end of file diff --git a/advvfdipp/device_base.py b/advvfdipp/device_base.py new file mode 100644 index 0000000..6e4a3e4 --- /dev/null +++ b/advvfdipp/device_base.py @@ -0,0 +1,360 @@ +import types +import traceback +import binascii +import threading +import time +import thread +import os +import struct +import sys +import textwrap +import Queue +import json + + +class deviceBase(): + + def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None, companyId=None, offset=None, mqtt=None, Nodes=None): + self.offset = offset + self.company = companyId + self.name = name + self.number = number + self.q = Q + self.deviceName = name + '_[' + mac + ':' + number[0:2] + ':' + number[2:] + ']!' + self.chName = "M1" + '_[' + mac + ':' + self.chName2 = '_[' + mac + ':' + print 'device name is:' + print self.deviceName + mac2 = mac.replace(":", "") + self.mac = mac2.upper() + self.address = 1 + self.debug = True + self.mcu = mcu + self.firstRun = True + self.mqtt = mqtt + self.nodes = Nodes + #local dictionary of derived nodes ex: localNodes[tank_0199] = self + self.localNodes = {} + os.system("chmod 777 /root/reboot") + os.system("echo nameserver 8.8.8.8 > /etc/resolv.conf") + #Queue for imcoming sets + self.loraQ = Queue.Queue() + + self.knownIDs = [] + thread.start_new_thread(self.getSetsThread, ()) + + def getSetsThread(self): + + while True: + try: + item = self.loraQ.get(block=True, timeout=600) + try: + print "here is the item from the sets q" + print item + if len(item) == 2: + techname = str(json.loads(item[1])[0]['payload']['name'].split(".")[0]) + channel = str(json.loads(item[1])[0]['payload']['name'].split(".")[1]) + name = techname.split("_")[0] + id = techname.split("_")[1][1:-2].replace(":","").upper() + value = json.loads(item[1])[0]['payload']['value'] + msgId = json.loads(item[1])[0]['msgId'] + + print channel, value, id, name, msgId + success = self.specificSets(channel, value, id, name) + + if success == True: + print "SUCCESS ON SET" + if int(msgId) == 0: + return + lc = self.getTime() + + value = str(self.mac) + " Success Setting: " + channel + " To: " + value + msg = """[ { "value":"%s", "timestamp":"%s", "msgId":"%s" } ]""" % (value, str(lc), msgId) + print value + print msg + topic = "meshify/responses/" + str(msgId) + print topic + self.q.put([topic, str(msg), 2]) + + + else: + + lc = self.getTime() + if success == False: + reason = "(Internal Gateway/Device Error)" + else: + reason = success + value = str(self.mac) + " Failed Setting: " + channel + " To: " + value + " " + reason + msg = """[ { "value":"%s", "timestamp":"%s", "msgId":"%s" } ]""" % (value, str(lc), msgId) + topic = "meshify/responses/" + msgId + self.q.put([topic, str(msg), 2]) + + except: + if int(msgId) == 0: + return + lc = self.getTime() + value = str(self.mac) + " Failed Setting: " + channel + " To: " + value + " (No Callback Found)" + msg = """[ { "value":"%s", "timestamp":"%s", "msgId":"%s" } ]""" % (value, str(lc), msgId) + topic = "meshify/responses/" + msgId + self.q.put([topic, str(msg), 2]) + print 'no Set callback found for channel: ' + funcName + + except: + print "sets queue timeout, restarting..." + + + def sendtodbDevLora(self, id, channel, value, timestamp, deviceName): + + + + mac = self.mac + + if deviceName == "mainMeshify": + zigmac = "_[01:00:00:00:00:" + id[0:2] + ":" + id[2:4] + ":" + id[4:6] + "]!" + else: + zigmac = "_[00:00:00:00:00:" + id[0:2] + ":" + id[2:4] + ":" + id[4:6] + "]!" + dname = deviceName + zigmac + + #define dname, make id into techname and mac + if id not in self.knownIDs: + self.knownIDs.append(id) + self.mcu.xbees[dname] = self.loraQ + + #meshify/db/330/C493000354FB/ilora/c493000354fb2A6E/a1-v + #[ { "value":"0.5635", "timestamp":"1486039316" } ] + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbLocLora(self, id, channel, value, timestamp, deviceName): + + + + mac = id + while len(mac) < 12: + mac = "0" + mac + if deviceName == "mainMeshify": + zigmac = "_[01:00:00:00:00:" + id[0:2] + ":" + id[2:4] + ":" + id[4:6] + "]!" + else: + zigmac = "_[00:00:00:00:00:" + id[0:2] + ":" + id[2:4] + ":" + id[4:6] + "]!" + dname = deviceName + zigmac + + #define dname, make id into techname and mac + if id not in self.knownIDs: + self.knownIDs.append(id) + topic = str(("meshify/sets/" + str(self.company) + "/" + mac + "/#")) + self.mqtt.subscribe(topic, 0) + topic = str(("meshify/sets/" + "1" + "/" + mac + "/#")) + self.mqtt.subscribe(topic, 0) + self.mcu.xbees[dname] = self.loraQ + + #meshify/db/330/C493000354FB/ilora/c493000354fb2A6E/a1-v + #[ { "value":"0.5635", "timestamp":"1486039316" } ] + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbLocLoraCom(self, id, channel, value, timestamp, deviceName): + + + + mac = "1" + id + while len(mac) < 12: + mac = "0" + mac + + if deviceName == "mainMeshify": + zigmac = "_[01:00:00:00:00:" + id[0:2] + ":" + id[2:4] + ":" + id[4:6] + "]!" + else: + zigmac = "_[00:00:00:00:01:" + id[0:2] + ":" + id[2:4] + ":" + id[4:6] + "]!" + dname = deviceName + zigmac + + #define dname, make id into techname and mac + if id not in self.knownIDs: + self.knownIDs.append(id) + topic = str(("meshify/sets/" + str(self.company) + "/" + mac + "/#")) + self.mqtt.subscribe(topic, 0) + topic = str(("meshify/sets/" + "1" + "/" + mac + "/#")) + self.mqtt.subscribe(topic, 0) + self.mcu.xbees[dname] = self.loraQ + + #meshify/db/330/C493000354FB/ilora/c493000354fb2A6E/a1-v + #[ { "value":"0.5635", "timestamp":"1486039316" } ] + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbLoc(self, ch, channel, value, timestamp, deviceName, mac): + + + #this will add your derived nodes the master nodes list, allowing them to receive sets!! + localNodesName = deviceName + "_" + str(ch) + "99" + + if not self.localNodes.has_key(localNodesName): + self.localNodes[localNodesName] = True + self.nodes[localNodesName] = self + + #make the techname + lst = textwrap.wrap(str(mac), width=2) + tech = "" + for i in range(len(lst)): + tech += lst[i].lower() + ":" + + + chName2 = '_[' + tech + + if int(ch) < 10: + ch = "0" + str(int(ch)) + + if len(ch) > 2: + ch = ch[:-2] + + dname = deviceName + chName2 + str(ch) + ":98]!" + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbDevJSON(self, ch, channel, value, timestamp, deviceName): + + if int(ch) < 10: + ch = "0" + str(int(ch)) + dname = deviceName + self.chName2 + str(ch) + ":99]!" + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, self.mac, dname, channel) + print topic + msg = """[ { "value":%s, "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbLora(self, ch, channel, value, timestamp, deviceName): + + if ":" not in ch: + ch = ch[0:2] + ":" + ch[2:4] + + #this will add your derived nodes the master nodes list, allowing them to receive sets!! + localNodesName = deviceName + "_" + str(ch).replace(':', "") + + if not self.localNodes.has_key(localNodesName): + self.localNodes[localNodesName] = True + self.nodes[localNodesName] = self + + + + dname = deviceName + self.chName2 + str(ch) + "]!" + + + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, self.mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbDev(self, ch, channel, value, timestamp, deviceName): + + + #this will add your derived nodes the master nodes list, allowing them to receive sets!! + localNodesName = deviceName + "_" + str(ch) + "99" + + if not self.localNodes.has_key(localNodesName): + self.localNodes[localNodesName] = True + self.nodes[localNodesName] = self + + if int(ch) < 10: + ch = "0" + str(int(ch)) + + dname = deviceName + self.chName2 + str(ch) + ":99]!" + + + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, self.mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbCH(self, ch, channel, value, timestamp): + + + if int(ch) < 10: + ch = "0" + str(ch) + + dname = self.chName + str(ch) + ":99]!" + + + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, self.mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodb(self, channel, value, timestamp): + + if int(timestamp) == 0: + timestamp = self.getTime() + if timestamp < 1400499858: + return + else: + timestamp = str(int(timestamp) + int(self.offset)) + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, self.mac, self.deviceName, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbJSON(self, channel, value, timestamp): + + if int(timestamp) == 0: + timestamp = self.getTime() + if timestamp < 1400499858: + return + else: + timestamp = str(int(timestamp) + int(self.offset)) + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, self.mac, self.deviceName, channel) + print topic + msg = """[ { "value":%s, "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + def getTime(self): + return str(int(time.time() + int(self.offset))) + + + + diff --git a/advvfdipp/driverConfig.json b/advvfdipp/driverConfig.json new file mode 100644 index 0000000..e643321 --- /dev/null +++ b/advvfdipp/driverConfig.json @@ -0,0 +1,14 @@ +{ + "name": "advvfdipp", + "driverFilename": "advvfdipp.py", + "driverId": "0000", + "additionalDriverFiles": [ + "utilities.py", + "persistence.py", + "Channel.py", + "logger.py", + "Tags.py" + ], + "version": 1, + "s3BucketName": "advvfdipp" +} diff --git a/advvfdipp/file_logger.py b/advvfdipp/file_logger.py new file mode 100644 index 0000000..74f2297 --- /dev/null +++ b/advvfdipp/file_logger.py @@ -0,0 +1,18 @@ +"""Logging setup for advvfdipp""" +import logging +from logging.handlers import RotatingFileHandler +import sys + +log_formatter = logging.Formatter('%(asctime)s %(levelname)s %(funcName)s(%(lineno)d) %(message)s') +log_file = './advvfdipp.log' +my_handler = RotatingFileHandler(log_file, mode='a', maxBytes=500*1024, + backupCount=2, encoding=None, delay=0) +my_handler.setFormatter(log_formatter) +my_handler.setLevel(logging.INFO) +filelogger = logging.getLogger('advvfdipp') +filelogger.setLevel(logging.INFO) +filelogger.addHandler(my_handler) + +console_out = logging.StreamHandler(sys.stdout) +console_out.setFormatter(log_formatter) +filelogger.addHandler(console_out) diff --git a/advvfdipp/persistence.py b/advvfdipp/persistence.py new file mode 100644 index 0000000..8c8703f --- /dev/null +++ b/advvfdipp/persistence.py @@ -0,0 +1,21 @@ +"""Data persistance functions.""" +# if more advanced persistence is needed, use a sqlite database +import json + + +def load(filename="persist.json"): + """Load persisted settings from the specified file.""" + try: + with open(filename, 'r') as persist_file: + return json.load(persist_file) + except Exception: + return False + + +def store(persist_obj, filename="persist.json"): + """Store the persisting settings into the specified file.""" + try: + with open(filename, 'w') as persist_file: + return json.dump(persist_obj, persist_file, indent=4) + except Exception: + return False diff --git a/advvfdipppond/advvfdipppond.py b/advvfdipppond/advvfdipppond.py index 2f518bf..381d7fa 100644 --- a/advvfdipppond/advvfdipppond.py +++ b/advvfdipppond/advvfdipppond.py @@ -84,13 +84,23 @@ class start(threading.Thread, deviceBase): mqtt=mqtt, Nodes=Nodes) self.daemon = True - self.version = "2" + self.version = "3" self.finished = threading.Event() self.force_send = False self.public_ip_address = "" self.private_ip_address = "" self.public_ip_address_last_checked = 0 self.ping_counter = 0 + deviceMap = {} + with open("drivers/deviceMap.json", "r") as dm: + deviceMap = json.load(dm) + with open("provision.json", "w+") as creds: + p = { + "deviceName": deviceMap[mac], + "provisionDeviceKey": "lkc7ra5l4dnyp782d3px", + "provisionDeviceSecret": "p6olkitsteiwkf1pv7m5" + } + json.dump(p, creds, indent=4) threading.Thread.start(self) # this is a required function for all drivers, its goal is to upload some piece of data diff --git a/advvfdipppond/config.txt b/advvfdipppond/config.txt index cc5dc47..8f967fb 100644 --- a/advvfdipppond/config.txt +++ b/advvfdipppond/config.txt @@ -5,10 +5,11 @@ "file1": "advvfdipppond.py", "file6": "persistence.py", "file5": "utilities.py", - "file4": "Tags.py" + "file4": "Tags.py", + "file5": "deviceMap.json" }, "deviceName": "advvfdipppond", - "releaseVersion": "2", + "releaseVersion": "3", "driverFileName": "advvfdipppond.py", "driverId": "0100" } \ No newline at end of file diff --git a/advvfdipppond/deviceMap.json b/advvfdipppond/deviceMap.json new file mode 100644 index 0000000..fa7dc7c --- /dev/null +++ b/advvfdipppond/deviceMap.json @@ -0,0 +1,292 @@ +{ + "c4:93:00:0e:d5:03": "Nail Ranch 37 SR 2-3", + "c4:93:00:0c:68:36": "Wrage 21 SR 2-2", + "c4:93:00:08:d0:11": "Wrage 28 SR 2-2", + "b8:27:eb:46:8d:7d": "Free 40 WS 2-2", + "b8:27:eb:78:03:88": "Wilkinson 1 WS 1-9", + "b8:27:eb:86:b6:dc": "Wilkinson 1 WS 1-10B", + "b8:27:eb:06:b1:94": "Wilkinson 39 WS 1-3", + "b8:27:eb:02:2f:f0": "Wilkinson 4 WS 1-10", + "b8:27:eb:c1:ac:f5": "Horton 34 WS 10-5", + "c4:93:00:0a:89:f5": "Bowling WW 4-1", + "c4:93:00:08:d0:65": "Banay WW 7-1", + "c4:93:00:0e:e9:c1": "Banay WW 5-1", + "c4:93:00:09:51:ce": "Bowling WW 37-1", + "c4:93:00:0c:68:57": "Banay WW 504", + "c4:93:00:0d:f2:68": "Banay WW 18 #4", + "c4:93:00:0d:bb:48": "Banay WW 18 #9", + "00:00:01:00:00:05": "Windham 108-1", + "00:00:01:00:00:07": "Windham 108-3", + "c4:93:00:08:d4:49": "Wrage Ranch 32 SR 1-1", + "b8:27:eb:68:43:70": "LimeQuest 5 WS 10-10", + "00:00:00:00:00:02": "Florence WW #2", + "00:00:00:00:00:03": "Florence WW #1", + "00:00:00:00:00:11": "Madelyn Kate #3 WW", + "00:00:00:00:00:14": "Jessica WW #3", + "00:00:01:00:00:01": "Windham 108-7", + "00:00:01:00:00:02": "Windham 108-6", + "00:00:01:00:00:03": "Windham 108-5", + "00:00:01:00:00:04": "Windham 107-1", + "00:00:01:00:00:08": "Windham 107-2", + "00:00:01:00:00:09": "Windham 108-8", + "00:00:01:00:00:10": "Windham 108-10", + "00:00:01:00:00:11": "Windham 108-2", + "00:00:01:00:00:12": "Windham 108-9", + "00:00:00:00:00:18": "Jessica WW #7", + "c4:93:00:0d:f1:6c": "Faudree Frac Pit Pump #1", + "c4:93:00:0d:f2:8c": "Faudree Frac Pit Pump #2", + "c4:93:00:03:af:34": "Wilkinson Ranch 34 SR 2-2", + "c4:93:00:05:dd:a2": "Nail Ranch 2 SR 3-3", + "c4:93:00:03:54:c5": "Nail Ranch 38 SR 2-3", + "c4:93:00:03:69:c8": "Nail Ranch 25 SR 2-1", + "c4:93:00:05:dd:ed": "Nail Ranch 28 SR 3-3", + "c4:93:00:03:56:7b": "Nail Ranch 38 SR 1-3", + "c4:93:00:03:6b:12": "Nail Ranch 3 SR 3-2", + "c4:93:00:03:7f:b2": "Nail Ranch 28 SR 2-2", + "c4:93:00:05:85:1f": "Nail Ranch 28 SR 1-1", + "c4:93:00:03:6b:2d": "Guitar 22 SR 3-3", + "c4:93:00:0c:d2:29": "Wilkinson Ranch 33 SR 2-2", + "c4:93:00:0c:67:af": "Wilkinson Ranch 35 SR 1-1", + "c4:93:00:0c:aa:75": "Wilkinson Ranch 1 SR 2-2", + "c4:93:00:0d:f3:55": "Limequest Transfer Lite", + "c4:93:00:0d:f2:5c": "S. Wilkinson Transfer Lite", + "c4:93:00:0d:f2:8f": "Nail Ranch 2 SR 2-2", + "c4:93:00:0d:f0:ca": "Horton Transfer Lite", + "c4:93:00:0d:f2:b0": "South Wilkinson Transfer #2", + "b8:27:eb:16:f0:64": "Wilkinson 39 WS 1-5", + "b8:27:eb:d8:64:a6": "Wilkinson 39 WS 1-4", + "b8:27:eb:5a:1c:1e": "Wilkinson 39 WS 1-2", + "b8:27:eb:a0:e9:f9": "Free 40 WS 1-2", + "b8:27:eb:da:8d:ea": "Wilkinson 39 WS 1-1", + "b8:27:eb:9a:2e:f0": "Free 32 WS 3-10C", + "b8:27:eb:06:d1:c0": "Free 40 WS 5-6", + "b8:27:eb:75:d2:6a": "Free 40 WS 1-4", + "b8:27:eb:e0:0b:2c": "Free 40 WS 1-6", + "b8:27:eb:01:75:8e": "Free 32 WS 3-10A", + "b8:27:eb:06:2e:17": "Wilkinson 34 WS 9-10", + "b8:27:eb:6d:7f:6c": "Wilkinson 33 WS 10-3A", + "b8:27:eb:7d:e9:f8": "Wilkinson 33 WS 10-3B", + "b8:27:eb:1c:c4:49": "Wilkinson 33 WS 10-1B", + "b8:27:eb:f9:71:92": "Wilkinson 33 WS 6-7", + "b8:27:eb:d4:cb:e4": "Free 32 WS 3-10B", + "b8:27:eb:0e:6a:13": "LimeQuest 5 WS 9-9", + "b8:27:eb:2b:d6:59": "LimeQuest 5 WS 6-8", + "b8:27:eb:92:a0:18": "LimeQuest 5 WS 2-4", + "b8:27:eb:92:65:df": "LimeQuest 5 WS 8-5", + "b8:27:eb:5c:4e:e4": "LimeQuest 5 WS 7-5", + "b8:27:eb:0e:2e:f2": "LimeQuest 5 WS 4-7", + "b8:27:eb:c4:7e:50": "Horton 23 WS 5-6", + "b8:27:eb:1e:a1:f7": "Horton 23 WS 8-6", + "b8:27:eb:fa:2d:73": "Horton 23 WS 6-6", + "b8:27:eb:bd:3b:55": "Horton 34 WS 1-2", + "b8:27:eb:a7:7f:6f": "Horton 23 WS 5-2", + "b8:27:eb:2f:c5:8c": "Horton 23 WS 5-5", + "b8:27:eb:e9:c5:7d": "Wilkinson 37 WS 1-9B", + "b8:27:eb:96:a0:2d": "Wilkinson 39 WS 2-2", + "c4:93:00:0d:bb:42": "Wilkinson 37 WS 1-8", + "b8:27:eb:b8:9b:a7": "Wilkinson 1 WS 9-4B", + "c4:93:00:0d:bb:45": "ToolBox South", + "c4:93:00:08:cf:c0": "Carmanita WW 12-2", + "c4:93:00:08:cf:ba": "Carmanita WW 12-1", + "c4:93:00:08:cf:0c": "Banay North Frac Pit", + "c4:93:00:08:d4:31": "Banay South Frac Pit", + "c4:93:00:0a:8a:0d": "Banay South Inlet", + "c4:93:00:09:4c:ee": "Banay WW 18 #3", + "c4:93:00:0b:0c:d5": "Carmanita WW 12-3", + "c4:93:00:0c:aa:ff": "Banay WW 8-5", + "c4:93:00:0d:f1:5d": "Banay WW 8-2", + "c4:93:00:0d:e8:9f": "Banay WW 6-1", + "c4:93:00:0d:f1:87": "Banay WW 18 #10", + "c4:93:00:03:7c:dc": "Carmanita WW 12-4", + "c4:93:00:0d:f5:56": "Banay WW 18 #1", + "00:00:00:00:00:04": "Caden WW #1", + "00:00:00:00:00:05": "Caden WW #2", + "00:00:00:00:00:06": "Caden WW #3", + "00:00:00:00:00:07": "Caden WW #4", + "00:00:00:00:00:09": "Lisa WW #1", + "00:00:00:00:00:08": "Caden WW #6", + "00:00:00:00:00:16": "Laurie Gwen WW #1", + "00:00:00:00:00:10": "Jessica WW #4", + "00:00:00:00:00:12": "Jessica WW #1", + "00:00:00:00:00:13": "Jessica WW #2", + "b8:27:eb:a9:df:e5": "Denali East Frac Pit", + "c4:93:00:0d:f1:c0": "Banay WW 8-4", + "00:00:00:00:00:17": "Jessica WW #5", + "c4:93:00:0b:0c:f6": "Map Rock Transfer Pump Monitor", + "b8:27:eb:aa:8a:53": "LimeQuest 5 WS 7-9", + "c4:93:00:09:51:bf": "Banay North Pit Inlet #1", + "c4:93:00:0d:f2:b9": "Banay North Pit Outlet #1", + "c4:93:00:0d:f5:44": "Yvonne Frac Pit", + "b8:27:eb:be:09:91": "Denali Frac Pit", + "b8:27:eb:df:53:70": "Horton 34 WS 1-4", + "00:00:02:00:00:02": "Cindy #1", + "00:00:02:00:00:08": "Cindy #3", + "00:00:02:00:00:11": "Cindy #2", + "00:00:03:00:00:03": "Lindsey #3", + "00:00:02:00:00:09": "Elizabeth 1", + "00:00:02:00:00:13": "Railway 12-3", + "00:00:02:00:00:14": "Railway 12-2", + "00:00:02:00:00:15": "Elizabeth B1", + "00:00:02:00:00:16": "Elizabeth B2", + "00:00:02:00:00:17": "Rhonda 1", + "00:00:02:00:00:18": "Sec 46 #1", + "00:00:02:00:00:19": "Cynthia 1", + "00:00:02:00:00:20": "Nancy #2", + "00:00:02:00:00:21": "Nancy #1", + "00:00:02:00:00:22": "Rhonda Pit", + "00:00:03:00:00:05": "Jitterbug 28-1", + "00:00:03:00:00:06": "Reagan #1", + "00:00:00:00:00:19": "Aurora 7", + "00:00:00:00:00:20": "Aurora 8", + "00:00:00:00:00:21": "Aurora 9", + "00:00:00:00:00:22": "Aurora 10", + "00:00:00:00:00:23": "Aurora 11", + "00:00:00:00:00:24": "Aurora 6", + "00:00:05:00:00:01": "RebJean #2", + "00:00:05:00:00:02": "Terri #6", + "00:00:05:00:00:03": "RobJane #2", + "00:00:05:00:00:04": "RobJane #3", + "00:00:05:00:00:05": "RebJean #1", + "00:00:05:00:00:06": "RobJane #1", + "00:00:05:00:00:07": "Kelsey #2", + "00:00:05:00:00:09": "Stephanie 41 #2", + "00:00:05:00:00:10": "Kelsey #1", + "00:00:05:00:00:11": "Stephanie 41 #3", + "00:00:05:00:00:12": "RobJane #4", + "00:00:05:00:00:16": "Terri #2", + "00:00:05:00:00:15": "Terri #1", + "00:00:05:00:00:14": "Terri #3", + "00:00:05:00:00:13": "Terri #4", + "b8:27:eb:80:2e:f7": "LimeQuest 5 WS 3-5", + "00:00:05:00:00:18": "Mary 43 #3", + "00:00:05:00:00:19": "Mary 43 #5", + "00:00:05:00:00:20": "Mary 43 #2", + "00:00:05:00:00:21": "Mary 43 #1", + "00:00:05:00:00:22": "KD #2", + "00:00:05:00:00:23": "KD #4", + "00:00:05:00:00:24": "KD #7", + "00:00:05:00:00:25": "KD #5", + "00:00:02:00:00:01": "Bobbie #1", + "00:00:02:00:00:03": "Bobbie #2", + "00:00:02:00:00:04": "Elizabeth A1", + "00:00:02:00:00:05": "Patty #1", + "c4:93:00:0d:f2:80": "Free Transfer Pit", + "00:00:02:00:00:06": "Rhonda 2", + "b8:27:eb:10:f5:1c": "Wilkinson 34 WS 5-10", + "b8:27:eb:c6:4d:a1": "Wilkinson 33 WS 5-2", + "b8:27:eb:fc:49:51": "Wilkinson 33 WS 6-3", + "b8:27:eb:1c:72:30": "Wilkinson 37 WS 7-8", + "b8:27:eb:ce:5d:4c": "Wilkinson 33 WS 4-1", + "b8:27:eb:b8:e9:52": "Wilkinson 37 WS 8-8", + "b8:27:eb:d8:b8:b6": "Wilkinson 34 WS 1-8", + "b8:27:eb:4f:f2:44": "Wilkinson 39 WS 2-4", + "00:00:00:00:00:25": "Trumann 1", + "00:00:00:00:00:26": "Trumann 3", + "00:00:00:00:00:27": "Trumann 4", + "00:00:00:00:00:28": "Trumann 5", + "00:00:00:00:00:29": "Trumann 2", + "00:00:02:00:00:07": "Patty #2", + "b8:27:eb:a6:a8:9a": "Wilkinson 37 WS 10-9", + "b8:27:eb:e4:44:da": "Wilkinson 33 WS 3-1", + "b8:27:eb:e0:0b:44": "Wilkinson 34 WS 2-10", + "b8:27:eb:8c:68:2a": "Wilkinson 37 WS 1-5", + "b8:27:eb:9b:fe:97": "Wilkinson 37 WS 3-5", + "b8:27:eb:0e:b3:e2": "Wilkinson 37 WS 3-6", + "b8:27:eb:d6:93:8b": "Wilkinson 37 WS 5-7", + "00:00:01:00:00:14": "Kate A1", + "00:00:01:00:00:15": "Kate A2", + "00:00:01:00:00:16": "Kate B1", + "00:00:01:00:00:17": "Tessa Lyn", + "00:00:02:00:00:10": "Patty #3", + "00:00:05:00:00:26": "Smith #1", + "00:00:05:00:00:27": "Smith #2", + "00:00:05:00:00:28": "Dorcus", + "00:00:06:00:00:01": "Monique #1", + "00:00:06:00:00:02": "Monique #2", + "00:00:06:00:00:03": "Monique #3", + "00:00:06:00:00:04": "Dawn #2", + "00:00:06:00:00:05": "Dawn #3", + "00:00:02:00:00:24": "Yvonne Transfer Pump 3", + "00:00:02:00:00:25": "Yvonne Transfer Pump 2", + "00:00:02:00:00:26": "Yvonne Transfer Pump 1", + "00:00:02:00:00:27": "Bobbie #3", + "00:00:05:00:00:29": "Kelsey Pit", + "b8:27:eb:83:24:8c": "Wilkinson 34 WS 10-9", + "c4:93:00:0d:f0:01": "Banay WW 18 #5", + "b8:27:eb:e5:59:03": "Wilkinson 39 WS 1-10", + "b8:27:eb:c8:1c:07": "Wilkinson 37 WS 4-7", + "c4:93:00:0d:ef:fb": "Banay WW 5-2", + "c4:93:00:0d:e8:69": "Banay WW 8-3", + "c4:93:00:0d:ef:53": "Banay WW 18 #7", + "c4:93:00:0d:f0:0d": "Banay WW 806 North", + "c4:93:00:0d:e8:75": "Banay WW 806 South", + "00:00:07:00:00:01": "Banay WW 18 #8", + "c4:93:00:0d:f3:73": "Denali East Inlet", + "b8:27:eb:18:05:d6": "Wilkinson 39 WS 2-8", + "c4:93:00:0d:f1:36": "Wilkinson Ranch 39 SR 1-1", + "c4:93:00:0d:e0:ef": "Wilkinson 37 WS 1-7", + "b8:27:eb:62:ed:99": "LimeQuest 5 WS 8-9", + "b8:27:eb:ca:94:0f": "LimeQuest 5 WS 1-4", + "b8:27:eb:47:eb:ae": "LimeQuest 10 WS 3-6", + "c4:93:00:0b:0c:c9": "Wrage 33 SR 3-3", + "c4:93:00:0d:f1:a8": "N. Wilkinson Transfer Lite", + "b8:27:eb:c6:e5:b3": "Wilkinson 33 WS 10-4", + "b8:27:eb:a9:be:d4": "Wilkinson 34 WS 9-9", + "00:00:03:00:00:01": "Lindsey #1", + "00:00:03:00:00:02": "Lindsey #2", + "b8:27:eb:95:68:93": "Wilkinson 1 WS 2-10", + "b8:27:eb:56:42:2b": "Wilkinson 33 ws 10-1A", + "c4:93:00:0d:f2:89": "Denali East Transfer Pump Monitor", + "c4:93:00:08:c6:81": "Map Rock Transfer Pump Monitor #2", + "b8:27:eb:47:6b:9d": "Wilkinson 37 WS 1-10", + "b8:27:eb:51:cc:bc": "Wilkinson 1 WS 1-10A", + "b8:27:eb:eb:6a:81": "Horton 34 WS 1-3", + "b8:27:eb:19:83:ab": "Wilkinson 39 ws 3-8", + "b8:27:eb:5e:49:a6": "Wilkinson 34 WS 6-10", + "b8:27:eb:6e:7b:1b": "Free 40 SR 2-1", + "c4:93:00:08:d4:13": "Nail Ranch 12 SR 1-3", + "b8:27:eb:5d:dd:09": "Wilkinson 33 WS 6-2", + "b8:27:eb:fd:a2:43": "Wilkinson 39 WS 1-7", + "b8:27:eb:d1:bc:61": "Wilkinson 2 WS 2-9", + "c4:93:00:0d:e9:41": "Dawn Frac Pit", + "b8:27:eb:8a:a9:65": "Wilkinson 34 WS 10-10", + "b8:27:eb:a8:41:f0": "Wilkinson 39 WS 2-10", + "b8:27:eb:7c:d7:c5": "Free 40 WS 1-1", + "00:00:00:00:00:01": "Barnett 19-2 WW", + "00:00:00:00:00:31": "Barnett 24-1", + "b8:27:eb:42:c3:4c": "Wilkinson 39 WS 1-6", + "c4:93:00:08:cf:18": "ToolBox North", + "b8:27:eb:50:ee:26": "Wilkinson 33 WS 10-2", + "c4:93:00:0b:0c:de": "Nail Ranch 37 SR 3-2", + "b8:27:eb:28:f9:49": "Wilkinson 37 WS 8-6", + "00:00:02:00:00:28": "Nancy Pit", + "c4:93:00:0d:e9:53": "Banay WW 18 #2", + "c4:93:00:0d:ef:26": "Banay WW 18 #6", + "c4:93:00:0d:f1:c6": "Banay WW 6-2", + "c4:93:00:0d:e9:3e": "Banay WW #7", + "00:18:05:1e:ae:b8": "Banay WW 7-2", + "00:18:05:1f:8d:0b": "Penny North", + "00:18:05:1f:8d:0e": "Penny South", + "b8:27:eb:96:3c:23": "Wilkinson 37 WS 5-5", + "c4:93:00:06:71:aa": "LLL 6 SR 1-1", + "b8:27:eb:48:aa:63": "Wilkinson 39 WS 1-9", + "b8:27:eb:40:0e:b2": "Wilkinson 39 WS 1-8", + "b8:27:eb:2d:86:50": "Wilkinson 39 WS 2-6", + "b8:27:eb:01:6c:fc": "LimeQuest 5 WS 10-9", + "b8:27:eb:28:e1:d6": "Baylee Pit", + "00:00:06:00:00:06": "Dawn to Terri", + "c4:93:00:0e:e9:ee": "Baylee Pit Transfer", + "00:00:05:00:00:31": "TM1", + "00:00:05:00:00:30": "TM2", + "00:00:05:00:00:32": "WC41-1", + "00:00:05:00:00:33": "WC41-2", + "00:00:05:00:00:34": "WC41-3", + "00:00:00:00:00:33": "Jordan Pit Pump#1", + "00:00:00:00:00:34": "Jordan Pit Pump #2", + "00:00:00:00:00:35": "Jessica #6", + "c4:93:00:0d:f2:41": "Jones A", + "00:00:01:00:00:23": "Kelly #1", + "00:00:01:00:00:24": "Kelly #2", + "00:00:01:00:00:25": "Kelly #3", + "02:42:ac:11:00:04": "RPi Test Device" +} \ No newline at end of file diff --git a/maplehmi/Channel.py b/maplehmi/Channel.py new file mode 100644 index 0000000..b25020a --- /dev/null +++ b/maplehmi/Channel.py @@ -0,0 +1,293 @@ +"""Define Meshify channel class.""" +import time +from pycomm.ab_comm.clx import Driver as ClxDriver +from pycomm.cip.cip_base import CommError, DataError +from file_logger import filelogger as log + + + +TAG_DATAERROR_SLEEPTIME = 5 + +def binarray(intval): + """Split an integer into its bits.""" + bin_string = '{0:08b}'.format(intval) + bin_arr = [i for i in bin_string] + bin_arr.reverse() + return bin_arr + + +def read_tag(addr, tag, plc_type="CLX"): + """Read a tag from the PLC.""" + direct = plc_type == "Micro800" + clx = ClxDriver() + try: + if clx.open(addr, direct_connection=direct): + try: + val = clx.read_tag(tag) + return val + except DataError as err: + clx.close() + time.sleep(TAG_DATAERROR_SLEEPTIME) + log.error("Data Error during readTag({}, {}): {}".format(addr, tag, err)) + except CommError: + # err = c.get_status() + clx.close() + log.error("Could not connect during readTag({}, {})".format(addr, tag)) + except AttributeError as err: + clx.close() + log.error("AttributeError during readTag({}, {}): \n{}".format(addr, tag, err)) + clx.close() + return False + + +def read_array(addr, tag, start, end, plc_type="CLX"): + """Read an array from the PLC.""" + direct = plc_type == "Micro800" + clx = ClxDriver() + if clx.open(addr, direct_connection=direct): + arr_vals = [] + try: + for i in range(start, end): + tag_w_index = tag + "[{}]".format(i) + val = clx.read_tag(tag_w_index) + arr_vals.append(round(val[0], 4)) + if arr_vals: + return arr_vals + else: + log.error("No length for {}".format(addr)) + return False + except Exception: + log.error("Error during readArray({}, {}, {}, {})".format(addr, tag, start, end)) + err = clx.get_status() + clx.close() + log.error(err) + clx.close() + + +def write_tag(addr, tag, val, plc_type="CLX"): + """Write a tag value to the PLC.""" + direct = plc_type == "Micro800" + clx = ClxDriver() + try: + if clx.open(addr, direct_connection=direct): + try: + initial_val = clx.read_tag(tag) + write_status = clx.write_tag(tag, val, initial_val[1]) + return write_status + except DataError as err: + clx_err = clx.get_status() + clx.close() + log.error("--\nDataError during writeTag({}, {}, {}, plc_type={}) -- {}\n{}\n".format(addr, tag, val, plc_type, err, clx_err)) + + except CommError as err: + clx_err = clx.get_status() + log.error("--\nCommError during write_tag({}, {}, {}, plc_type={})\n{}\n--".format(addr, tag, val, plc_type, err)) + clx.close() + return False + + +class Channel(object): + """Holds the configuration for a Meshify channel.""" + + def __init__(self, mesh_name, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False): + """Initialize the channel.""" + self.mesh_name = mesh_name + self.data_type = data_type + self.last_value = None + self.value = None + self.last_send_time = 0 + self.chg_threshold = chg_threshold + self.guarantee_sec = guarantee_sec + self.map_ = map_ + self.write_enabled = write_enabled + + def __str__(self): + """Create a string for the channel.""" + return "{}\nvalue: {}, last_send_time: {}".format(self.mesh_name, self.value, self.last_send_time) + + def check(self, new_value, force_send=False): + """Check to see if the new_value needs to be stored.""" + send_needed = False + send_reason = "" + if self.data_type == 'BOOL' or self.data_type == 'STRING': + if self.last_send_time == 0: + send_needed = True + send_reason = "no send time" + elif self.value is None: + send_needed = True + send_reason = "no value" + elif self.value != new_value: + if self.map_: + if not self.value == self.map_[new_value]: + send_needed = True + send_reason = "value change" + else: + send_needed = True + send_reason = "value change" + elif (time.time() - self.last_send_time) > self.guarantee_sec: + send_needed = True + send_reason = "guarantee sec" + elif force_send: + send_needed = True + send_reason = "forced" + else: + if self.last_send_time == 0: + send_needed = True + send_reason = "no send time" + elif self.value is None: + send_needed = True + send_reason = "no value" + elif abs(self.value - new_value) > self.chg_threshold: + send_needed = True + send_reason = "change threshold" + elif (time.time() - self.last_send_time) > self.guarantee_sec: + send_needed = True + send_reason = "guarantee sec" + elif force_send: + send_needed = True + send_reason = "forced" + if send_needed: + self.last_value = self.value + if self.map_: + try: + self.value = self.map_[new_value] + except KeyError: + log.error("Cannot find a map value for {} in {} for {}".format(new_value, self.map_, self.mesh_name)) + self.value = new_value + else: + self.value = new_value + self.last_send_time = time.time() + log.info("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) + return send_needed + + def read(self): + """Read the value.""" + pass + + +def identity(sent): + """Return exactly what was sent to it.""" + return sent + + +class ModbusChannel(Channel): + """Modbus channel object.""" + + def __init__(self, mesh_name, register_number, data_type, chg_threshold, guarantee_sec, channel_size=1, map_=False, write_enabled=False, transform_fn=identity): + """Initialize the channel.""" + super(ModbusChannel, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled) + self.mesh_name = mesh_name + self.register_number = register_number + self.channel_size = channel_size + self.data_type = data_type + self.last_value = None + self.value = None + self.last_send_time = 0 + self.chg_threshold = chg_threshold + self.guarantee_sec = guarantee_sec + self.map_ = map_ + self.write_enabled = write_enabled + self.transform_fn = transform_fn + + def read(self, mbsvalue): + """Return the transformed read value.""" + return self.transform_fn(mbsvalue) + + +class PLCChannel(Channel): + """PLC Channel Object.""" + + def __init__(self, ip, mesh_name, plc_tag, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False, plc_type='CLX'): + """Initialize the channel.""" + super(PLCChannel, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled) + self.plc_ip = ip + self.mesh_name = mesh_name + self.plc_tag = plc_tag + self.data_type = data_type + self.last_value = None + self.value = None + self.last_send_time = 0 + self.chg_threshold = chg_threshold + self.guarantee_sec = guarantee_sec + self.map_ = map_ + self.write_enabled = write_enabled + self.plc_type = plc_type + + def read(self): + """Read the value.""" + plc_value = None + if self.plc_tag and self.plc_ip: + read_value = read_tag(self.plc_ip, self.plc_tag, plc_type=self.plc_type) + if read_value: + plc_value = read_value[0] + + return plc_value + + +class BoolArrayChannels(Channel): + """Hold the configuration for a set of boolean array channels.""" + + def __init__(self, ip, mesh_name, plc_tag, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False): + """Initialize the channel.""" + super(BoolArrayChannels, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled) + self.plc_ip = ip + self.mesh_name = mesh_name + self.plc_tag = plc_tag + self.data_type = data_type + self.last_value = None + self.value = None + self.last_send_time = 0 + self.chg_threshold = chg_threshold + self.guarantee_sec = guarantee_sec + self.map_ = map_ + self.write_enabled = write_enabled + + def compare_values(self, new_val_dict): + """Compare new values to old values to see if the values need storing.""" + send = False + for idx in new_val_dict: + try: + if new_val_dict[idx] != self.last_value[idx]: + send = True + except KeyError: + log.error("Key Error in self.compare_values for index {}".format(idx)) + send = True + return send + + def read(self, force_send=False): + """Read the value and check to see if needs to be stored.""" + send_needed = False + send_reason = "" + if self.plc_tag: + val = read_tag(self.plc_ip, self.plc_tag) + if val: + bool_arr = binarray(val[0]) + new_val = {} + for idx in self.map_: + try: + new_val[self.map_[idx]] = bool_arr[idx] + except KeyError: + log.error("Not able to get value for index {}".format(idx)) + + if self.last_send_time == 0: + send_needed = True + send_reason = "no send time" + elif self.value is None: + send_needed = True + send_reason = "no value" + elif self.compare_values(new_val): + send_needed = True + send_reason = "value change" + elif (time.time() - self.last_send_time) > self.guarantee_sec: + send_needed = True + send_reason = "guarantee sec" + elif force_send: + send_needed = True + send_reason = "forced" + + if send_needed: + self.value = new_val + self.last_value = self.value + self.last_send_time = time.time() + log.info("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) + return send_needed diff --git a/maplehmi/Tags.py b/maplehmi/Tags.py new file mode 100644 index 0000000..12727a2 --- /dev/null +++ b/maplehmi/Tags.py @@ -0,0 +1,4 @@ +from Channel import PLCChannel, ModbusChannel +from maplehmi import PLC_IP_ADDRESS + +tags = [ ] diff --git a/maplehmi/config.txt b/maplehmi/config.txt new file mode 100644 index 0000000..1060b37 --- /dev/null +++ b/maplehmi/config.txt @@ -0,0 +1,14 @@ +{ + "files": { + "file3": "file_logger.py", + "file2": "Channel.py", + "file1": "maplehmi.py", + "file6": "persistence.py", + "file5": "utilities.py", + "file4": "Tags.py" + }, + "deviceName": "maplehmi", + "releaseVersion": "1", + "driverFileName": "maplehmi.py", + "driverId": "0100" +} \ No newline at end of file diff --git a/maplehmi/device_base.py b/maplehmi/device_base.py new file mode 100644 index 0000000..6e4a3e4 --- /dev/null +++ b/maplehmi/device_base.py @@ -0,0 +1,360 @@ +import types +import traceback +import binascii +import threading +import time +import thread +import os +import struct +import sys +import textwrap +import Queue +import json + + +class deviceBase(): + + def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None, companyId=None, offset=None, mqtt=None, Nodes=None): + self.offset = offset + self.company = companyId + self.name = name + self.number = number + self.q = Q + self.deviceName = name + '_[' + mac + ':' + number[0:2] + ':' + number[2:] + ']!' + self.chName = "M1" + '_[' + mac + ':' + self.chName2 = '_[' + mac + ':' + print 'device name is:' + print self.deviceName + mac2 = mac.replace(":", "") + self.mac = mac2.upper() + self.address = 1 + self.debug = True + self.mcu = mcu + self.firstRun = True + self.mqtt = mqtt + self.nodes = Nodes + #local dictionary of derived nodes ex: localNodes[tank_0199] = self + self.localNodes = {} + os.system("chmod 777 /root/reboot") + os.system("echo nameserver 8.8.8.8 > /etc/resolv.conf") + #Queue for imcoming sets + self.loraQ = Queue.Queue() + + self.knownIDs = [] + thread.start_new_thread(self.getSetsThread, ()) + + def getSetsThread(self): + + while True: + try: + item = self.loraQ.get(block=True, timeout=600) + try: + print "here is the item from the sets q" + print item + if len(item) == 2: + techname = str(json.loads(item[1])[0]['payload']['name'].split(".")[0]) + channel = str(json.loads(item[1])[0]['payload']['name'].split(".")[1]) + name = techname.split("_")[0] + id = techname.split("_")[1][1:-2].replace(":","").upper() + value = json.loads(item[1])[0]['payload']['value'] + msgId = json.loads(item[1])[0]['msgId'] + + print channel, value, id, name, msgId + success = self.specificSets(channel, value, id, name) + + if success == True: + print "SUCCESS ON SET" + if int(msgId) == 0: + return + lc = self.getTime() + + value = str(self.mac) + " Success Setting: " + channel + " To: " + value + msg = """[ { "value":"%s", "timestamp":"%s", "msgId":"%s" } ]""" % (value, str(lc), msgId) + print value + print msg + topic = "meshify/responses/" + str(msgId) + print topic + self.q.put([topic, str(msg), 2]) + + + else: + + lc = self.getTime() + if success == False: + reason = "(Internal Gateway/Device Error)" + else: + reason = success + value = str(self.mac) + " Failed Setting: " + channel + " To: " + value + " " + reason + msg = """[ { "value":"%s", "timestamp":"%s", "msgId":"%s" } ]""" % (value, str(lc), msgId) + topic = "meshify/responses/" + msgId + self.q.put([topic, str(msg), 2]) + + except: + if int(msgId) == 0: + return + lc = self.getTime() + value = str(self.mac) + " Failed Setting: " + channel + " To: " + value + " (No Callback Found)" + msg = """[ { "value":"%s", "timestamp":"%s", "msgId":"%s" } ]""" % (value, str(lc), msgId) + topic = "meshify/responses/" + msgId + self.q.put([topic, str(msg), 2]) + print 'no Set callback found for channel: ' + funcName + + except: + print "sets queue timeout, restarting..." + + + def sendtodbDevLora(self, id, channel, value, timestamp, deviceName): + + + + mac = self.mac + + if deviceName == "mainMeshify": + zigmac = "_[01:00:00:00:00:" + id[0:2] + ":" + id[2:4] + ":" + id[4:6] + "]!" + else: + zigmac = "_[00:00:00:00:00:" + id[0:2] + ":" + id[2:4] + ":" + id[4:6] + "]!" + dname = deviceName + zigmac + + #define dname, make id into techname and mac + if id not in self.knownIDs: + self.knownIDs.append(id) + self.mcu.xbees[dname] = self.loraQ + + #meshify/db/330/C493000354FB/ilora/c493000354fb2A6E/a1-v + #[ { "value":"0.5635", "timestamp":"1486039316" } ] + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbLocLora(self, id, channel, value, timestamp, deviceName): + + + + mac = id + while len(mac) < 12: + mac = "0" + mac + if deviceName == "mainMeshify": + zigmac = "_[01:00:00:00:00:" + id[0:2] + ":" + id[2:4] + ":" + id[4:6] + "]!" + else: + zigmac = "_[00:00:00:00:00:" + id[0:2] + ":" + id[2:4] + ":" + id[4:6] + "]!" + dname = deviceName + zigmac + + #define dname, make id into techname and mac + if id not in self.knownIDs: + self.knownIDs.append(id) + topic = str(("meshify/sets/" + str(self.company) + "/" + mac + "/#")) + self.mqtt.subscribe(topic, 0) + topic = str(("meshify/sets/" + "1" + "/" + mac + "/#")) + self.mqtt.subscribe(topic, 0) + self.mcu.xbees[dname] = self.loraQ + + #meshify/db/330/C493000354FB/ilora/c493000354fb2A6E/a1-v + #[ { "value":"0.5635", "timestamp":"1486039316" } ] + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbLocLoraCom(self, id, channel, value, timestamp, deviceName): + + + + mac = "1" + id + while len(mac) < 12: + mac = "0" + mac + + if deviceName == "mainMeshify": + zigmac = "_[01:00:00:00:00:" + id[0:2] + ":" + id[2:4] + ":" + id[4:6] + "]!" + else: + zigmac = "_[00:00:00:00:01:" + id[0:2] + ":" + id[2:4] + ":" + id[4:6] + "]!" + dname = deviceName + zigmac + + #define dname, make id into techname and mac + if id not in self.knownIDs: + self.knownIDs.append(id) + topic = str(("meshify/sets/" + str(self.company) + "/" + mac + "/#")) + self.mqtt.subscribe(topic, 0) + topic = str(("meshify/sets/" + "1" + "/" + mac + "/#")) + self.mqtt.subscribe(topic, 0) + self.mcu.xbees[dname] = self.loraQ + + #meshify/db/330/C493000354FB/ilora/c493000354fb2A6E/a1-v + #[ { "value":"0.5635", "timestamp":"1486039316" } ] + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbLoc(self, ch, channel, value, timestamp, deviceName, mac): + + + #this will add your derived nodes the master nodes list, allowing them to receive sets!! + localNodesName = deviceName + "_" + str(ch) + "99" + + if not self.localNodes.has_key(localNodesName): + self.localNodes[localNodesName] = True + self.nodes[localNodesName] = self + + #make the techname + lst = textwrap.wrap(str(mac), width=2) + tech = "" + for i in range(len(lst)): + tech += lst[i].lower() + ":" + + + chName2 = '_[' + tech + + if int(ch) < 10: + ch = "0" + str(int(ch)) + + if len(ch) > 2: + ch = ch[:-2] + + dname = deviceName + chName2 + str(ch) + ":98]!" + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbDevJSON(self, ch, channel, value, timestamp, deviceName): + + if int(ch) < 10: + ch = "0" + str(int(ch)) + dname = deviceName + self.chName2 + str(ch) + ":99]!" + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, self.mac, dname, channel) + print topic + msg = """[ { "value":%s, "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbLora(self, ch, channel, value, timestamp, deviceName): + + if ":" not in ch: + ch = ch[0:2] + ":" + ch[2:4] + + #this will add your derived nodes the master nodes list, allowing them to receive sets!! + localNodesName = deviceName + "_" + str(ch).replace(':', "") + + if not self.localNodes.has_key(localNodesName): + self.localNodes[localNodesName] = True + self.nodes[localNodesName] = self + + + + dname = deviceName + self.chName2 + str(ch) + "]!" + + + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, self.mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbDev(self, ch, channel, value, timestamp, deviceName): + + + #this will add your derived nodes the master nodes list, allowing them to receive sets!! + localNodesName = deviceName + "_" + str(ch) + "99" + + if not self.localNodes.has_key(localNodesName): + self.localNodes[localNodesName] = True + self.nodes[localNodesName] = self + + if int(ch) < 10: + ch = "0" + str(int(ch)) + + dname = deviceName + self.chName2 + str(ch) + ":99]!" + + + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, self.mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbCH(self, ch, channel, value, timestamp): + + + if int(ch) < 10: + ch = "0" + str(ch) + + dname = self.chName + str(ch) + ":99]!" + + + + if int(timestamp) == 0: + timestamp = self.getTime() + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, self.mac, dname, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodb(self, channel, value, timestamp): + + if int(timestamp) == 0: + timestamp = self.getTime() + if timestamp < 1400499858: + return + else: + timestamp = str(int(timestamp) + int(self.offset)) + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, self.mac, self.deviceName, channel) + print topic + msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + + def sendtodbJSON(self, channel, value, timestamp): + + if int(timestamp) == 0: + timestamp = self.getTime() + if timestamp < 1400499858: + return + else: + timestamp = str(int(timestamp) + int(self.offset)) + + topic = 'meshify/db/%s/%s/%s/%s' % (self.company, self.mac, self.deviceName, channel) + print topic + msg = """[ { "value":%s, "timestamp":"%s" } ]""" % (str(value), str(timestamp)) + print msg + self.q.put([topic, msg, 0]) + def getTime(self): + return str(int(time.time() + int(self.offset))) + + + + diff --git a/maplehmi/driverConfig.json b/maplehmi/driverConfig.json new file mode 100644 index 0000000..641a616 --- /dev/null +++ b/maplehmi/driverConfig.json @@ -0,0 +1,14 @@ +{ + "name": "maplehmi", + "driverFilename": "maplehmi.py", + "driverId": "0000", + "additionalDriverFiles": [ + "utilities.py", + "persistence.py", + "Channel.py", + "logger.py", + "Tags.py" + ], + "version": 1, + "s3BucketName": "maplehmi" +} diff --git a/maplehmi/file_logger.py b/maplehmi/file_logger.py new file mode 100644 index 0000000..91df345 --- /dev/null +++ b/maplehmi/file_logger.py @@ -0,0 +1,18 @@ +"""Logging setup for maplehmi""" +import logging +from logging.handlers import RotatingFileHandler +import sys + +log_formatter = logging.Formatter('%(asctime)s %(levelname)s %(funcName)s(%(lineno)d) %(message)s') +log_file = './maplehmi.log' +my_handler = RotatingFileHandler(log_file, mode='a', maxBytes=500*1024, + backupCount=2, encoding=None, delay=0) +my_handler.setFormatter(log_formatter) +my_handler.setLevel(logging.INFO) +filelogger = logging.getLogger('maplehmi') +filelogger.setLevel(logging.INFO) +filelogger.addHandler(my_handler) + +console_out = logging.StreamHandler(sys.stdout) +console_out.setFormatter(log_formatter) +filelogger.addHandler(console_out) diff --git a/maplehmi/maplehmi.py b/maplehmi/maplehmi.py new file mode 100644 index 0000000..b2af18e --- /dev/null +++ b/maplehmi/maplehmi.py @@ -0,0 +1,148 @@ +"""Driver for maplehmi""" + +import threading +import json +import time +from random import randint + +from device_base import deviceBase +from Channel import PLCChannel, ModbusChannel,read_tag, write_tag, TAG_DATAERROR_SLEEPTIME +import persistence +from utilities import get_public_ip_address +from file_logger import filelogger as log +PLC_IP_ADDRESS = "192.168.1.10" +from Tags import tags + +_ = None + +log.info("maplehmi startup") + +# GLOBAL VARIABLES +WAIT_FOR_CONNECTION_SECONDS = 60 +IP_CHECK_PERIOD = 60 +WATCHDOG_ENABLE = True +WATCHDOG_CHECK_PERIOD = 60 +WATCHDOG_SEND_PERIOD = 3600 # Seconds, the longest amount of time before sending the watchdog status + +CHANNELS = tags + +# PERSISTENCE FILE +PERSIST = persistence.load() + + +class start(threading.Thread, deviceBase): + """Start class required by Meshify.""" + + def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None, + companyId=None, offset=None, mqtt=None, Nodes=None): + """Initialize the driver.""" + threading.Thread.__init__(self) + deviceBase.__init__(self, name=name, number=number, mac=mac, Q=Q, + mcu=mcu, companyId=companyId, offset=offset, + mqtt=mqtt, Nodes=Nodes) + + self.daemon = True + self.version = "1" + self.finished = threading.Event() + self.force_send = False + self.public_ip_address = "" + self.public_ip_address_last_checked = 0 + self.watchdog = False + self.watchdog_last_checked = 0 + self.watchdog_last_sent = 0 + threading.Thread.start(self) + + # this is a required function for all drivers, its goal is to upload some piece of data + # about your device so it can be seen on the web + def register(self): + """Register the driver.""" + # self.sendtodb("log", "BOOM! Booted.", 0) + pass + + def run(self): + """Actually run the driver.""" + for i in range(0, WAIT_FOR_CONNECTION_SECONDS): + print("maplehmi driver will start in {} seconds".format(WAIT_FOR_CONNECTION_SECONDS - i)) + time.sleep(1) + log.info("BOOM! Starting maplehmi driver...") + + self._check_watchdog() + self._check_ip_address() + + self.nodes["maplehmi_0199"] = self + + send_loops = 0 + + while True: + now = time.time() + if self.force_send: + log.warning("FORCE SEND: TRUE") + + for chan in CHANNELS: + val = chan.read() + if chan.check(val, self.force_send): + self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'maplehmi') + time.sleep(TAG_DATAERROR_SLEEPTIME) # sleep to allow Micro800 to handle ENET requests + + # print("maplehmi driver still alive...") + if self.force_send: + if send_loops > 2: + log.warning("Turning off force_send") + self.force_send = False + send_loops = 0 + else: + send_loops += 1 + + if WATCHDOG_ENABLE: + if (now - self.watchdog_last_checked) > WATCHDOG_CHECK_PERIOD: + self._check_watchdog() + + if (now - self.public_ip_address_last_checked) > IP_CHECK_PERIOD: + self._check_ip_address() + + def _check_watchdog(self): + """Check the watchdog and send to Meshify if changed or stale.""" + test_watchdog = self.maplehmi_watchdog() + now = time.time() + self.watchdog_last_checked = now + if test_watchdog != self.watchdog or (now - self.watchdog_last_sent) > WATCHDOG_SEND_PERIOD: + self.sendtodbDev(1, 'watchdog', test_watchdog, 0, 'maplehmi') + self.watchdog = test_watchdog + self.watchdog_last_sent = now + + + def _check_ip_address(self): + """Check the public IP address and send to Meshify if changed.""" + self.public_ip_address_last_checked = time.time() + test_public_ip = get_public_ip_address() + if not test_public_ip == self.public_ip_address: + self.sendtodbDev(1, 'public_ip_address', test_public_ip, 0, 'maplehmi') + self.public_ip_address = test_public_ip + + def maplehmi_watchdog(self): + """Write a random integer to the PLC and then 1 seconds later check that it has been decremented by 1.""" + randval = randint(0, 32767) + write_tag(str(PLC_IP_ADDRESS), 'watchdog_INT', randval, plc_type="CLX") + time.sleep(1) + watchdog_val = read_tag(str(PLC_IP_ADDRESS), 'watchdog_INT', plc_type="CLX") + try: + return (randval - 1) == watchdog_val[0] + except (KeyError, TypeError): + return False + + def maplehmi_sync(self, name, value): + """Sync all data from the driver.""" + self.force_send = True + # self.sendtodb("log", "synced", 0) + return True + + def maplehmi_writeplctag(self, name, value): + """Write a value to the PLC.""" + new_val = json.loads(str(value).replace("'", '"')) + tag_n = str(new_val['tag']) # "cmd_Start" + val_n = new_val['val'] + write_res = write_tag(str(PLC_IP_ADDRESS), tag_n, val_n, plc_type="CLX") + print("Result of maplehmi_writeplctag(self, {}, {}) = {}".format(name, value, write_res)) + if write_res is None: + write_res = "Error writing to PLC..." + return write_res diff --git a/maplehmi/persistence.py b/maplehmi/persistence.py new file mode 100644 index 0000000..8c8703f --- /dev/null +++ b/maplehmi/persistence.py @@ -0,0 +1,21 @@ +"""Data persistance functions.""" +# if more advanced persistence is needed, use a sqlite database +import json + + +def load(filename="persist.json"): + """Load persisted settings from the specified file.""" + try: + with open(filename, 'r') as persist_file: + return json.load(persist_file) + except Exception: + return False + + +def store(persist_obj, filename="persist.json"): + """Store the persisting settings into the specified file.""" + try: + with open(filename, 'w') as persist_file: + return json.dump(persist_obj, persist_file, indent=4) + except Exception: + return False diff --git a/maplehmi/utilities.py b/maplehmi/utilities.py new file mode 100644 index 0000000..7e88d62 --- /dev/null +++ b/maplehmi/utilities.py @@ -0,0 +1,52 @@ +"""Utility functions for the driver.""" +import socket +import struct + + +def get_public_ip_address(): + """Find the public IP Address of the host device.""" + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.connect(("8.8.8.8", 80)) + ip_address = sock.getsockname()[0] + sock.close() + except Exception as e: + return e + return ip_address + + +def int_to_float16(int_to_convert): + """Convert integer into float16 representation.""" + bin_rep = ('0' * 16 + '{0:b}'.format(int_to_convert))[-16:] + sign = 1.0 + if int(bin_rep[0]) == 1: + sign = -1.0 + exponent = float(int(bin_rep[1:6], 2)) + fraction = float(int(bin_rep[6:17], 2)) + + if exponent == float(0b00000): + return sign * 2 ** -14 * fraction / (2.0 ** 10.0) + elif exponent == float(0b11111): + if fraction == 0: + return sign * float("inf") + return float("NaN") + frac_part = 1.0 + fraction / (2.0 ** 10.0) + return sign * (2 ** (exponent - 15)) * frac_part + + +def ints_to_float(int1, int2): + """Convert 2 registers into a floating point number.""" + mypack = struct.pack('>HH', int1, int2) + f_unpacked = struct.unpack('>f', mypack) + print("[{}, {}] >> {}".format(int1, int2, f_unpacked[0])) + return f_unpacked[0] + + +def degf_to_degc(temp_f): + """Convert deg F to deg C.""" + return (temp_f - 32.0) * (5.0/9.0) + + +def degc_to_degf(temp_c): + """Convert deg C to deg F.""" + return temp_c * 1.8 + 32.0 diff --git a/piflow/PiFlow.py b/piflow/PiFlow.py index 8bf5291..60afca6 100644 --- a/piflow/PiFlow.py +++ b/piflow/PiFlow.py @@ -103,7 +103,7 @@ class start(threading.Thread, deviceBase): mqtt=mqtt, Nodes=Nodes) self.daemon = True - self.version = "28" + self.version = "29" self.finished = threading.Event() self.force_send = False self.public_ip_address = "" @@ -114,7 +114,16 @@ class start(threading.Thread, deviceBase): self.rts = RTS() self.rts.loadDataFromFile() self.rts.saveDataToFile() - + deviceMap = {} + with open("drivers/deviceMap.json", "r") as dm: + deviceMap = json.load(dm) + with open("provision.json", "w+") as creds: + p = { + "deviceName": deviceMap[mac], + "provisionDeviceKey": "509hpmpppl1bz8scficf", + "provisionDeviceSecret": "1qgo53a6b0vg36n8ll1t" + } + json.dump(p, creds, indent=4) threading.Thread.start(self) # this is a required function for all drivers, its goal is to upload some piece of data diff --git a/piflow/config.txt b/piflow/config.txt index 3a5efaf..620b17e 100644 --- a/piflow/config.txt +++ b/piflow/config.txt @@ -3,7 +3,7 @@ "driverFileName":"PiFlow.py", "deviceName":"piflow", "driverId":"0280", -"releaseVersion":"28", +"releaseVersion":"29", "files": { "file1":"PiFlow.py", "file2":"Channel.py", @@ -11,7 +11,9 @@ "file4":"Tags.py", "file5":"utilities.py", "file6":"persistence.py", - "file7":"runtimeStats.py" + "file7":"runtimeStats.py", + "file8": "deviceMap.json", + "file9": "modbusTester.py" } } \ No newline at end of file diff --git a/piflow/deviceMap.json b/piflow/deviceMap.json new file mode 100644 index 0000000..fa7dc7c --- /dev/null +++ b/piflow/deviceMap.json @@ -0,0 +1,292 @@ +{ + "c4:93:00:0e:d5:03": "Nail Ranch 37 SR 2-3", + "c4:93:00:0c:68:36": "Wrage 21 SR 2-2", + "c4:93:00:08:d0:11": "Wrage 28 SR 2-2", + "b8:27:eb:46:8d:7d": "Free 40 WS 2-2", + "b8:27:eb:78:03:88": "Wilkinson 1 WS 1-9", + "b8:27:eb:86:b6:dc": "Wilkinson 1 WS 1-10B", + "b8:27:eb:06:b1:94": "Wilkinson 39 WS 1-3", + "b8:27:eb:02:2f:f0": "Wilkinson 4 WS 1-10", + "b8:27:eb:c1:ac:f5": "Horton 34 WS 10-5", + "c4:93:00:0a:89:f5": "Bowling WW 4-1", + "c4:93:00:08:d0:65": "Banay WW 7-1", + "c4:93:00:0e:e9:c1": "Banay WW 5-1", + "c4:93:00:09:51:ce": "Bowling WW 37-1", + "c4:93:00:0c:68:57": "Banay WW 504", + "c4:93:00:0d:f2:68": "Banay WW 18 #4", + "c4:93:00:0d:bb:48": "Banay WW 18 #9", + "00:00:01:00:00:05": "Windham 108-1", + "00:00:01:00:00:07": "Windham 108-3", + "c4:93:00:08:d4:49": "Wrage Ranch 32 SR 1-1", + "b8:27:eb:68:43:70": "LimeQuest 5 WS 10-10", + "00:00:00:00:00:02": "Florence WW #2", + "00:00:00:00:00:03": "Florence WW #1", + "00:00:00:00:00:11": "Madelyn Kate #3 WW", + "00:00:00:00:00:14": "Jessica WW #3", + "00:00:01:00:00:01": "Windham 108-7", + "00:00:01:00:00:02": "Windham 108-6", + "00:00:01:00:00:03": "Windham 108-5", + "00:00:01:00:00:04": "Windham 107-1", + "00:00:01:00:00:08": "Windham 107-2", + "00:00:01:00:00:09": "Windham 108-8", + "00:00:01:00:00:10": "Windham 108-10", + "00:00:01:00:00:11": "Windham 108-2", + "00:00:01:00:00:12": "Windham 108-9", + "00:00:00:00:00:18": "Jessica WW #7", + "c4:93:00:0d:f1:6c": "Faudree Frac Pit Pump #1", + "c4:93:00:0d:f2:8c": "Faudree Frac Pit Pump #2", + "c4:93:00:03:af:34": "Wilkinson Ranch 34 SR 2-2", + "c4:93:00:05:dd:a2": "Nail Ranch 2 SR 3-3", + "c4:93:00:03:54:c5": "Nail Ranch 38 SR 2-3", + "c4:93:00:03:69:c8": "Nail Ranch 25 SR 2-1", + "c4:93:00:05:dd:ed": "Nail Ranch 28 SR 3-3", + "c4:93:00:03:56:7b": "Nail Ranch 38 SR 1-3", + "c4:93:00:03:6b:12": "Nail Ranch 3 SR 3-2", + "c4:93:00:03:7f:b2": "Nail Ranch 28 SR 2-2", + "c4:93:00:05:85:1f": "Nail Ranch 28 SR 1-1", + "c4:93:00:03:6b:2d": "Guitar 22 SR 3-3", + "c4:93:00:0c:d2:29": "Wilkinson Ranch 33 SR 2-2", + "c4:93:00:0c:67:af": "Wilkinson Ranch 35 SR 1-1", + "c4:93:00:0c:aa:75": "Wilkinson Ranch 1 SR 2-2", + "c4:93:00:0d:f3:55": "Limequest Transfer Lite", + "c4:93:00:0d:f2:5c": "S. Wilkinson Transfer Lite", + "c4:93:00:0d:f2:8f": "Nail Ranch 2 SR 2-2", + "c4:93:00:0d:f0:ca": "Horton Transfer Lite", + "c4:93:00:0d:f2:b0": "South Wilkinson Transfer #2", + "b8:27:eb:16:f0:64": "Wilkinson 39 WS 1-5", + "b8:27:eb:d8:64:a6": "Wilkinson 39 WS 1-4", + "b8:27:eb:5a:1c:1e": "Wilkinson 39 WS 1-2", + "b8:27:eb:a0:e9:f9": "Free 40 WS 1-2", + "b8:27:eb:da:8d:ea": "Wilkinson 39 WS 1-1", + "b8:27:eb:9a:2e:f0": "Free 32 WS 3-10C", + "b8:27:eb:06:d1:c0": "Free 40 WS 5-6", + "b8:27:eb:75:d2:6a": "Free 40 WS 1-4", + "b8:27:eb:e0:0b:2c": "Free 40 WS 1-6", + "b8:27:eb:01:75:8e": "Free 32 WS 3-10A", + "b8:27:eb:06:2e:17": "Wilkinson 34 WS 9-10", + "b8:27:eb:6d:7f:6c": "Wilkinson 33 WS 10-3A", + "b8:27:eb:7d:e9:f8": "Wilkinson 33 WS 10-3B", + "b8:27:eb:1c:c4:49": "Wilkinson 33 WS 10-1B", + "b8:27:eb:f9:71:92": "Wilkinson 33 WS 6-7", + "b8:27:eb:d4:cb:e4": "Free 32 WS 3-10B", + "b8:27:eb:0e:6a:13": "LimeQuest 5 WS 9-9", + "b8:27:eb:2b:d6:59": "LimeQuest 5 WS 6-8", + "b8:27:eb:92:a0:18": "LimeQuest 5 WS 2-4", + "b8:27:eb:92:65:df": "LimeQuest 5 WS 8-5", + "b8:27:eb:5c:4e:e4": "LimeQuest 5 WS 7-5", + "b8:27:eb:0e:2e:f2": "LimeQuest 5 WS 4-7", + "b8:27:eb:c4:7e:50": "Horton 23 WS 5-6", + "b8:27:eb:1e:a1:f7": "Horton 23 WS 8-6", + "b8:27:eb:fa:2d:73": "Horton 23 WS 6-6", + "b8:27:eb:bd:3b:55": "Horton 34 WS 1-2", + "b8:27:eb:a7:7f:6f": "Horton 23 WS 5-2", + "b8:27:eb:2f:c5:8c": "Horton 23 WS 5-5", + "b8:27:eb:e9:c5:7d": "Wilkinson 37 WS 1-9B", + "b8:27:eb:96:a0:2d": "Wilkinson 39 WS 2-2", + "c4:93:00:0d:bb:42": "Wilkinson 37 WS 1-8", + "b8:27:eb:b8:9b:a7": "Wilkinson 1 WS 9-4B", + "c4:93:00:0d:bb:45": "ToolBox South", + "c4:93:00:08:cf:c0": "Carmanita WW 12-2", + "c4:93:00:08:cf:ba": "Carmanita WW 12-1", + "c4:93:00:08:cf:0c": "Banay North Frac Pit", + "c4:93:00:08:d4:31": "Banay South Frac Pit", + "c4:93:00:0a:8a:0d": "Banay South Inlet", + "c4:93:00:09:4c:ee": "Banay WW 18 #3", + "c4:93:00:0b:0c:d5": "Carmanita WW 12-3", + "c4:93:00:0c:aa:ff": "Banay WW 8-5", + "c4:93:00:0d:f1:5d": "Banay WW 8-2", + "c4:93:00:0d:e8:9f": "Banay WW 6-1", + "c4:93:00:0d:f1:87": "Banay WW 18 #10", + "c4:93:00:03:7c:dc": "Carmanita WW 12-4", + "c4:93:00:0d:f5:56": "Banay WW 18 #1", + "00:00:00:00:00:04": "Caden WW #1", + "00:00:00:00:00:05": "Caden WW #2", + "00:00:00:00:00:06": "Caden WW #3", + "00:00:00:00:00:07": "Caden WW #4", + "00:00:00:00:00:09": "Lisa WW #1", + "00:00:00:00:00:08": "Caden WW #6", + "00:00:00:00:00:16": "Laurie Gwen WW #1", + "00:00:00:00:00:10": "Jessica WW #4", + "00:00:00:00:00:12": "Jessica WW #1", + "00:00:00:00:00:13": "Jessica WW #2", + "b8:27:eb:a9:df:e5": "Denali East Frac Pit", + "c4:93:00:0d:f1:c0": "Banay WW 8-4", + "00:00:00:00:00:17": "Jessica WW #5", + "c4:93:00:0b:0c:f6": "Map Rock Transfer Pump Monitor", + "b8:27:eb:aa:8a:53": "LimeQuest 5 WS 7-9", + "c4:93:00:09:51:bf": "Banay North Pit Inlet #1", + "c4:93:00:0d:f2:b9": "Banay North Pit Outlet #1", + "c4:93:00:0d:f5:44": "Yvonne Frac Pit", + "b8:27:eb:be:09:91": "Denali Frac Pit", + "b8:27:eb:df:53:70": "Horton 34 WS 1-4", + "00:00:02:00:00:02": "Cindy #1", + "00:00:02:00:00:08": "Cindy #3", + "00:00:02:00:00:11": "Cindy #2", + "00:00:03:00:00:03": "Lindsey #3", + "00:00:02:00:00:09": "Elizabeth 1", + "00:00:02:00:00:13": "Railway 12-3", + "00:00:02:00:00:14": "Railway 12-2", + "00:00:02:00:00:15": "Elizabeth B1", + "00:00:02:00:00:16": "Elizabeth B2", + "00:00:02:00:00:17": "Rhonda 1", + "00:00:02:00:00:18": "Sec 46 #1", + "00:00:02:00:00:19": "Cynthia 1", + "00:00:02:00:00:20": "Nancy #2", + "00:00:02:00:00:21": "Nancy #1", + "00:00:02:00:00:22": "Rhonda Pit", + "00:00:03:00:00:05": "Jitterbug 28-1", + "00:00:03:00:00:06": "Reagan #1", + "00:00:00:00:00:19": "Aurora 7", + "00:00:00:00:00:20": "Aurora 8", + "00:00:00:00:00:21": "Aurora 9", + "00:00:00:00:00:22": "Aurora 10", + "00:00:00:00:00:23": "Aurora 11", + "00:00:00:00:00:24": "Aurora 6", + "00:00:05:00:00:01": "RebJean #2", + "00:00:05:00:00:02": "Terri #6", + "00:00:05:00:00:03": "RobJane #2", + "00:00:05:00:00:04": "RobJane #3", + "00:00:05:00:00:05": "RebJean #1", + "00:00:05:00:00:06": "RobJane #1", + "00:00:05:00:00:07": "Kelsey #2", + "00:00:05:00:00:09": "Stephanie 41 #2", + "00:00:05:00:00:10": "Kelsey #1", + "00:00:05:00:00:11": "Stephanie 41 #3", + "00:00:05:00:00:12": "RobJane #4", + "00:00:05:00:00:16": "Terri #2", + "00:00:05:00:00:15": "Terri #1", + "00:00:05:00:00:14": "Terri #3", + "00:00:05:00:00:13": "Terri #4", + "b8:27:eb:80:2e:f7": "LimeQuest 5 WS 3-5", + "00:00:05:00:00:18": "Mary 43 #3", + "00:00:05:00:00:19": "Mary 43 #5", + "00:00:05:00:00:20": "Mary 43 #2", + "00:00:05:00:00:21": "Mary 43 #1", + "00:00:05:00:00:22": "KD #2", + "00:00:05:00:00:23": "KD #4", + "00:00:05:00:00:24": "KD #7", + "00:00:05:00:00:25": "KD #5", + "00:00:02:00:00:01": "Bobbie #1", + "00:00:02:00:00:03": "Bobbie #2", + "00:00:02:00:00:04": "Elizabeth A1", + "00:00:02:00:00:05": "Patty #1", + "c4:93:00:0d:f2:80": "Free Transfer Pit", + "00:00:02:00:00:06": "Rhonda 2", + "b8:27:eb:10:f5:1c": "Wilkinson 34 WS 5-10", + "b8:27:eb:c6:4d:a1": "Wilkinson 33 WS 5-2", + "b8:27:eb:fc:49:51": "Wilkinson 33 WS 6-3", + "b8:27:eb:1c:72:30": "Wilkinson 37 WS 7-8", + "b8:27:eb:ce:5d:4c": "Wilkinson 33 WS 4-1", + "b8:27:eb:b8:e9:52": "Wilkinson 37 WS 8-8", + "b8:27:eb:d8:b8:b6": "Wilkinson 34 WS 1-8", + "b8:27:eb:4f:f2:44": "Wilkinson 39 WS 2-4", + "00:00:00:00:00:25": "Trumann 1", + "00:00:00:00:00:26": "Trumann 3", + "00:00:00:00:00:27": "Trumann 4", + "00:00:00:00:00:28": "Trumann 5", + "00:00:00:00:00:29": "Trumann 2", + "00:00:02:00:00:07": "Patty #2", + "b8:27:eb:a6:a8:9a": "Wilkinson 37 WS 10-9", + "b8:27:eb:e4:44:da": "Wilkinson 33 WS 3-1", + "b8:27:eb:e0:0b:44": "Wilkinson 34 WS 2-10", + "b8:27:eb:8c:68:2a": "Wilkinson 37 WS 1-5", + "b8:27:eb:9b:fe:97": "Wilkinson 37 WS 3-5", + "b8:27:eb:0e:b3:e2": "Wilkinson 37 WS 3-6", + "b8:27:eb:d6:93:8b": "Wilkinson 37 WS 5-7", + "00:00:01:00:00:14": "Kate A1", + "00:00:01:00:00:15": "Kate A2", + "00:00:01:00:00:16": "Kate B1", + "00:00:01:00:00:17": "Tessa Lyn", + "00:00:02:00:00:10": "Patty #3", + "00:00:05:00:00:26": "Smith #1", + "00:00:05:00:00:27": "Smith #2", + "00:00:05:00:00:28": "Dorcus", + "00:00:06:00:00:01": "Monique #1", + "00:00:06:00:00:02": "Monique #2", + "00:00:06:00:00:03": "Monique #3", + "00:00:06:00:00:04": "Dawn #2", + "00:00:06:00:00:05": "Dawn #3", + "00:00:02:00:00:24": "Yvonne Transfer Pump 3", + "00:00:02:00:00:25": "Yvonne Transfer Pump 2", + "00:00:02:00:00:26": "Yvonne Transfer Pump 1", + "00:00:02:00:00:27": "Bobbie #3", + "00:00:05:00:00:29": "Kelsey Pit", + "b8:27:eb:83:24:8c": "Wilkinson 34 WS 10-9", + "c4:93:00:0d:f0:01": "Banay WW 18 #5", + "b8:27:eb:e5:59:03": "Wilkinson 39 WS 1-10", + "b8:27:eb:c8:1c:07": "Wilkinson 37 WS 4-7", + "c4:93:00:0d:ef:fb": "Banay WW 5-2", + "c4:93:00:0d:e8:69": "Banay WW 8-3", + "c4:93:00:0d:ef:53": "Banay WW 18 #7", + "c4:93:00:0d:f0:0d": "Banay WW 806 North", + "c4:93:00:0d:e8:75": "Banay WW 806 South", + "00:00:07:00:00:01": "Banay WW 18 #8", + "c4:93:00:0d:f3:73": "Denali East Inlet", + "b8:27:eb:18:05:d6": "Wilkinson 39 WS 2-8", + "c4:93:00:0d:f1:36": "Wilkinson Ranch 39 SR 1-1", + "c4:93:00:0d:e0:ef": "Wilkinson 37 WS 1-7", + "b8:27:eb:62:ed:99": "LimeQuest 5 WS 8-9", + "b8:27:eb:ca:94:0f": "LimeQuest 5 WS 1-4", + "b8:27:eb:47:eb:ae": "LimeQuest 10 WS 3-6", + "c4:93:00:0b:0c:c9": "Wrage 33 SR 3-3", + "c4:93:00:0d:f1:a8": "N. Wilkinson Transfer Lite", + "b8:27:eb:c6:e5:b3": "Wilkinson 33 WS 10-4", + "b8:27:eb:a9:be:d4": "Wilkinson 34 WS 9-9", + "00:00:03:00:00:01": "Lindsey #1", + "00:00:03:00:00:02": "Lindsey #2", + "b8:27:eb:95:68:93": "Wilkinson 1 WS 2-10", + "b8:27:eb:56:42:2b": "Wilkinson 33 ws 10-1A", + "c4:93:00:0d:f2:89": "Denali East Transfer Pump Monitor", + "c4:93:00:08:c6:81": "Map Rock Transfer Pump Monitor #2", + "b8:27:eb:47:6b:9d": "Wilkinson 37 WS 1-10", + "b8:27:eb:51:cc:bc": "Wilkinson 1 WS 1-10A", + "b8:27:eb:eb:6a:81": "Horton 34 WS 1-3", + "b8:27:eb:19:83:ab": "Wilkinson 39 ws 3-8", + "b8:27:eb:5e:49:a6": "Wilkinson 34 WS 6-10", + "b8:27:eb:6e:7b:1b": "Free 40 SR 2-1", + "c4:93:00:08:d4:13": "Nail Ranch 12 SR 1-3", + "b8:27:eb:5d:dd:09": "Wilkinson 33 WS 6-2", + "b8:27:eb:fd:a2:43": "Wilkinson 39 WS 1-7", + "b8:27:eb:d1:bc:61": "Wilkinson 2 WS 2-9", + "c4:93:00:0d:e9:41": "Dawn Frac Pit", + "b8:27:eb:8a:a9:65": "Wilkinson 34 WS 10-10", + "b8:27:eb:a8:41:f0": "Wilkinson 39 WS 2-10", + "b8:27:eb:7c:d7:c5": "Free 40 WS 1-1", + "00:00:00:00:00:01": "Barnett 19-2 WW", + "00:00:00:00:00:31": "Barnett 24-1", + "b8:27:eb:42:c3:4c": "Wilkinson 39 WS 1-6", + "c4:93:00:08:cf:18": "ToolBox North", + "b8:27:eb:50:ee:26": "Wilkinson 33 WS 10-2", + "c4:93:00:0b:0c:de": "Nail Ranch 37 SR 3-2", + "b8:27:eb:28:f9:49": "Wilkinson 37 WS 8-6", + "00:00:02:00:00:28": "Nancy Pit", + "c4:93:00:0d:e9:53": "Banay WW 18 #2", + "c4:93:00:0d:ef:26": "Banay WW 18 #6", + "c4:93:00:0d:f1:c6": "Banay WW 6-2", + "c4:93:00:0d:e9:3e": "Banay WW #7", + "00:18:05:1e:ae:b8": "Banay WW 7-2", + "00:18:05:1f:8d:0b": "Penny North", + "00:18:05:1f:8d:0e": "Penny South", + "b8:27:eb:96:3c:23": "Wilkinson 37 WS 5-5", + "c4:93:00:06:71:aa": "LLL 6 SR 1-1", + "b8:27:eb:48:aa:63": "Wilkinson 39 WS 1-9", + "b8:27:eb:40:0e:b2": "Wilkinson 39 WS 1-8", + "b8:27:eb:2d:86:50": "Wilkinson 39 WS 2-6", + "b8:27:eb:01:6c:fc": "LimeQuest 5 WS 10-9", + "b8:27:eb:28:e1:d6": "Baylee Pit", + "00:00:06:00:00:06": "Dawn to Terri", + "c4:93:00:0e:e9:ee": "Baylee Pit Transfer", + "00:00:05:00:00:31": "TM1", + "00:00:05:00:00:30": "TM2", + "00:00:05:00:00:32": "WC41-1", + "00:00:05:00:00:33": "WC41-2", + "00:00:05:00:00:34": "WC41-3", + "00:00:00:00:00:33": "Jordan Pit Pump#1", + "00:00:00:00:00:34": "Jordan Pit Pump #2", + "00:00:00:00:00:35": "Jessica #6", + "c4:93:00:0d:f2:41": "Jones A", + "00:00:01:00:00:23": "Kelly #1", + "00:00:01:00:00:24": "Kelly #2", + "00:00:01:00:00:25": "Kelly #3", + "02:42:ac:11:00:04": "RPi Test Device" +} \ No newline at end of file diff --git a/sync_to_aws.sh b/sync_to_aws.sh new file mode 100755 index 0000000..ca7fc71 --- /dev/null +++ b/sync_to_aws.sh @@ -0,0 +1,2 @@ +cd /Users/nico/Documents/GitHub/HenryPump-Drivers +aws s3 sync . s3://pocloud-drivers --acl public-read --exclude "*.DS_Store*" --exclude "*git*" --exclude "*.zip*" --exclude "*.sh*" --exclude "*pycache*" --exclude "*ipynb*" \ No newline at end of file diff --git a/sync_to_aws_dryrun.sh b/sync_to_aws_dryrun.sh new file mode 100755 index 0000000..e38fbe5 --- /dev/null +++ b/sync_to_aws_dryrun.sh @@ -0,0 +1,2 @@ +cd /Users/nico/Documents/GitHub/HenryPump-Drivers +aws s3 sync . s3://pocloud-drivers --acl public-read --exclude "*.DS_Store*" --exclude "*git*" --exclude "*.zip*" --exclude "*.sh*" --exclude "*pycache*" --exclude "*ipynb*" --dryrun \ No newline at end of file diff --git a/sync_to_local.sh b/sync_to_local.sh new file mode 100755 index 0000000..9772f9d --- /dev/null +++ b/sync_to_local.sh @@ -0,0 +1,2 @@ +cd /Users/nico/Documents/GitHub/HenryPump-Drivers +aws s3 sync s3://pocloud-drivers . --exclude "*.DS_Store*" --exclude "*git*" --exclude "*.zip*" --exclude "*.sh*" --exclude "*pycache*" --exclude "*ipynb*" \ No newline at end of file diff --git a/sync_to_local_dryrun.sh b/sync_to_local_dryrun.sh new file mode 100755 index 0000000..3981d6a --- /dev/null +++ b/sync_to_local_dryrun.sh @@ -0,0 +1,2 @@ +cd /Users/nico/Documents/GitHub/HenryPump-Drivers +aws s3 sync s3://pocloud-drivers . --exclude "*.DS_Store*" --exclude "*git*" --exclude "*.zip*" --exclude "*.sh*" --exclude "*pycache*" --exclude "*ipynb*" --dryrun \ No newline at end of file diff --git a/test/config.txt b/test/config.txt new file mode 100644 index 0000000..a1a83f9 --- /dev/null +++ b/test/config.txt @@ -0,0 +1,10 @@ +{ + "files": { + "file2": "utilities.py", + "file1": "test.py" + }, + "deviceName": "test", + "driverId": "0140", + "releaseVersion": "8", + "driverFileName": "test.py" +} \ No newline at end of file diff --git a/test/test.py b/test/test.py new file mode 100644 index 0000000..ba88657 --- /dev/null +++ b/test/test.py @@ -0,0 +1 @@ +# Test! \ No newline at end of file diff --git a/test/utilities.py b/test/utilities.py new file mode 100644 index 0000000..9be36de --- /dev/null +++ b/test/utilities.py @@ -0,0 +1 @@ +# UTILITIES \ No newline at end of file diff --git a/transferlite/Channel.py b/transferlite/Channel.py index 8d3e384..b25020a 100644 --- a/transferlite/Channel.py +++ b/transferlite/Channel.py @@ -1,9 +1,13 @@ """Define Meshify channel class.""" +import time from pycomm.ab_comm.clx import Driver as ClxDriver from pycomm.cip.cip_base import CommError, DataError -import time +from file_logger import filelogger as log + +TAG_DATAERROR_SLEEPTIME = 5 + def binarray(intval): """Split an integer into its bits.""" bin_string = '{0:08b}'.format(intval) @@ -15,74 +19,71 @@ def binarray(intval): def read_tag(addr, tag, plc_type="CLX"): """Read a tag from the PLC.""" direct = plc_type == "Micro800" - c = ClxDriver() + clx = ClxDriver() try: - if c.open(addr, direct_connection=direct): + if clx.open(addr, direct_connection=direct): try: - v = c.read_tag(tag) - return v - except DataError as e: - c.close() - print("Data Error during readTag({}, {}): {}".format(addr, tag, e)) + val = clx.read_tag(tag) + return val + except DataError as err: + clx.close() + time.sleep(TAG_DATAERROR_SLEEPTIME) + log.error("Data Error during readTag({}, {}): {}".format(addr, tag, err)) except CommError: # err = c.get_status() - c.close() - print("Could not connect during readTag({}, {})".format(addr, tag)) - # print err - except AttributeError as e: - c.close() - print("AttributeError during readTag({}, {}): \n{}".format(addr, tag, e)) - c.close() + clx.close() + log.error("Could not connect during readTag({}, {})".format(addr, tag)) + except AttributeError as err: + clx.close() + log.error("AttributeError during readTag({}, {}): \n{}".format(addr, tag, err)) + clx.close() return False def read_array(addr, tag, start, end, plc_type="CLX"): """Read an array from the PLC.""" direct = plc_type == "Micro800" - c = ClxDriver() - if c.open(addr, direct_connection=direct): + clx = ClxDriver() + if clx.open(addr, direct_connection=direct): arr_vals = [] try: for i in range(start, end): tag_w_index = tag + "[{}]".format(i) - v = c.read_tag(tag_w_index) - # print('{} - {}'.format(tag_w_index, v)) - arr_vals.append(round(v[0], 4)) - # print(v) - if len(arr_vals) > 0: + val = clx.read_tag(tag_w_index) + arr_vals.append(round(val[0], 4)) + if arr_vals: return arr_vals else: - print("No length for {}".format(addr)) + log.error("No length for {}".format(addr)) return False except Exception: - print("Error during readArray({}, {}, {}, {})".format(addr, tag, start, end)) - err = c.get_status() - c.close() - print(err) - c.close() + log.error("Error during readArray({}, {}, {}, {})".format(addr, tag, start, end)) + err = clx.get_status() + clx.close() + log.error(err) + clx.close() def write_tag(addr, tag, val, plc_type="CLX"): """Write a tag value to the PLC.""" direct = plc_type == "Micro800" - c = ClxDriver() + clx = ClxDriver() try: - if c.open(addr, direct_connection=direct): + if clx.open(addr, direct_connection=direct): try: - cv = c.read_tag(tag) - print(cv) - wt = c.write_tag(tag, val, cv[1]) - return wt - except Exception: - print("Error during writeTag({}, {}, {})".format(addr, tag, val)) - err = c.get_status() - c.close() - print(err) - c.close() - except CommError: - # err = c.get_status() - c.close() - print("Could not connect during writeTag({}, {}, {})".format(addr, tag, val)) + initial_val = clx.read_tag(tag) + write_status = clx.write_tag(tag, val, initial_val[1]) + return write_status + except DataError as err: + clx_err = clx.get_status() + clx.close() + log.error("--\nDataError during writeTag({}, {}, {}, plc_type={}) -- {}\n{}\n".format(addr, tag, val, plc_type, err, clx_err)) + + except CommError as err: + clx_err = clx.get_status() + log.error("--\nCommError during write_tag({}, {}, {}, plc_type={})\n{}\n--".format(addr, tag, val, plc_type, err)) + clx.close() + return False class Channel(object): @@ -115,7 +116,7 @@ class Channel(object): elif self.value is None: send_needed = True send_reason = "no value" - elif not (self.value == new_value): + elif self.value != new_value: if self.map_: if not self.value == self.map_[new_value]: send_needed = True @@ -151,12 +152,12 @@ class Channel(object): try: self.value = self.map_[new_value] except KeyError: - print("Cannot find a map value for {} in {} for {}".format(new_value, self.map_, self.mesh_name)) + log.error("Cannot find a map value for {} in {} for {}".format(new_value, self.map_, self.mesh_name)) self.value = new_value else: self.value = new_value self.last_send_time = time.time() - print("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) + log.info("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) return send_needed def read(self): @@ -172,7 +173,7 @@ def identity(sent): class ModbusChannel(Channel): """Modbus channel object.""" - def __init__(self, mesh_name, register_number, data_type, chg_threshold, guarantee_sec, channel_size=1, map_=False, write_enabled=False, transformFn=identity): + def __init__(self, mesh_name, register_number, data_type, chg_threshold, guarantee_sec, channel_size=1, map_=False, write_enabled=False, transform_fn=identity): """Initialize the channel.""" super(ModbusChannel, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled) self.mesh_name = mesh_name @@ -186,11 +187,11 @@ class ModbusChannel(Channel): self.guarantee_sec = guarantee_sec self.map_ = map_ self.write_enabled = write_enabled - self.transformFn = transformFn + self.transform_fn = transform_fn def read(self, mbsvalue): """Return the transformed read value.""" - return self.transformFn(mbsvalue) + return self.transform_fn(mbsvalue) class PLCChannel(Channel): @@ -228,6 +229,7 @@ class BoolArrayChannels(Channel): def __init__(self, ip, mesh_name, plc_tag, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False): """Initialize the channel.""" + super(BoolArrayChannels, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled) self.plc_ip = ip self.mesh_name = mesh_name self.plc_tag = plc_tag @@ -248,7 +250,7 @@ class BoolArrayChannels(Channel): if new_val_dict[idx] != self.last_value[idx]: send = True except KeyError: - print("Key Error in self.compare_values for index {}".format(idx)) + log.error("Key Error in self.compare_values for index {}".format(idx)) send = True return send @@ -257,15 +259,15 @@ class BoolArrayChannels(Channel): send_needed = False send_reason = "" if self.plc_tag: - v = read_tag(self.plc_ip, self.plc_tag) - if v: - bool_arr = binarray(v[0]) + val = read_tag(self.plc_ip, self.plc_tag) + if val: + bool_arr = binarray(val[0]) new_val = {} for idx in self.map_: try: new_val[self.map_[idx]] = bool_arr[idx] except KeyError: - print("Not able to get value for index {}".format(idx)) + log.error("Not able to get value for index {}".format(idx)) if self.last_send_time == 0: send_needed = True @@ -287,5 +289,5 @@ class BoolArrayChannels(Channel): self.value = new_val self.last_value = self.value self.last_send_time = time.time() - print("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) + log.info("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) return send_needed diff --git a/transferlite/config.txt b/transferlite/config.txt index 5f5d34a..aefc220 100644 --- a/transferlite/config.txt +++ b/transferlite/config.txt @@ -3,10 +3,11 @@ "file3": "channel.py", "file2": "utilities.py", "file1": "transferlite.py", - "file4": "file_logger.py" + "file4": "file_logger.py", + "file5": "deviceMap.json" }, "deviceName": "transferlite", "driverId": "0230", - "releaseVersion": "4", + "releaseVersion": "6", "driverFileName": "transferlite.py" } \ No newline at end of file diff --git a/transferlite/deviceMap.json b/transferlite/deviceMap.json new file mode 100644 index 0000000..fa7dc7c --- /dev/null +++ b/transferlite/deviceMap.json @@ -0,0 +1,292 @@ +{ + "c4:93:00:0e:d5:03": "Nail Ranch 37 SR 2-3", + "c4:93:00:0c:68:36": "Wrage 21 SR 2-2", + "c4:93:00:08:d0:11": "Wrage 28 SR 2-2", + "b8:27:eb:46:8d:7d": "Free 40 WS 2-2", + "b8:27:eb:78:03:88": "Wilkinson 1 WS 1-9", + "b8:27:eb:86:b6:dc": "Wilkinson 1 WS 1-10B", + "b8:27:eb:06:b1:94": "Wilkinson 39 WS 1-3", + "b8:27:eb:02:2f:f0": "Wilkinson 4 WS 1-10", + "b8:27:eb:c1:ac:f5": "Horton 34 WS 10-5", + "c4:93:00:0a:89:f5": "Bowling WW 4-1", + "c4:93:00:08:d0:65": "Banay WW 7-1", + "c4:93:00:0e:e9:c1": "Banay WW 5-1", + "c4:93:00:09:51:ce": "Bowling WW 37-1", + "c4:93:00:0c:68:57": "Banay WW 504", + "c4:93:00:0d:f2:68": "Banay WW 18 #4", + "c4:93:00:0d:bb:48": "Banay WW 18 #9", + "00:00:01:00:00:05": "Windham 108-1", + "00:00:01:00:00:07": "Windham 108-3", + "c4:93:00:08:d4:49": "Wrage Ranch 32 SR 1-1", + "b8:27:eb:68:43:70": "LimeQuest 5 WS 10-10", + "00:00:00:00:00:02": "Florence WW #2", + "00:00:00:00:00:03": "Florence WW #1", + "00:00:00:00:00:11": "Madelyn Kate #3 WW", + "00:00:00:00:00:14": "Jessica WW #3", + "00:00:01:00:00:01": "Windham 108-7", + "00:00:01:00:00:02": "Windham 108-6", + "00:00:01:00:00:03": "Windham 108-5", + "00:00:01:00:00:04": "Windham 107-1", + "00:00:01:00:00:08": "Windham 107-2", + "00:00:01:00:00:09": "Windham 108-8", + "00:00:01:00:00:10": "Windham 108-10", + "00:00:01:00:00:11": "Windham 108-2", + "00:00:01:00:00:12": "Windham 108-9", + "00:00:00:00:00:18": "Jessica WW #7", + "c4:93:00:0d:f1:6c": "Faudree Frac Pit Pump #1", + "c4:93:00:0d:f2:8c": "Faudree Frac Pit Pump #2", + "c4:93:00:03:af:34": "Wilkinson Ranch 34 SR 2-2", + "c4:93:00:05:dd:a2": "Nail Ranch 2 SR 3-3", + "c4:93:00:03:54:c5": "Nail Ranch 38 SR 2-3", + "c4:93:00:03:69:c8": "Nail Ranch 25 SR 2-1", + "c4:93:00:05:dd:ed": "Nail Ranch 28 SR 3-3", + "c4:93:00:03:56:7b": "Nail Ranch 38 SR 1-3", + "c4:93:00:03:6b:12": "Nail Ranch 3 SR 3-2", + "c4:93:00:03:7f:b2": "Nail Ranch 28 SR 2-2", + "c4:93:00:05:85:1f": "Nail Ranch 28 SR 1-1", + "c4:93:00:03:6b:2d": "Guitar 22 SR 3-3", + "c4:93:00:0c:d2:29": "Wilkinson Ranch 33 SR 2-2", + "c4:93:00:0c:67:af": "Wilkinson Ranch 35 SR 1-1", + "c4:93:00:0c:aa:75": "Wilkinson Ranch 1 SR 2-2", + "c4:93:00:0d:f3:55": "Limequest Transfer Lite", + "c4:93:00:0d:f2:5c": "S. Wilkinson Transfer Lite", + "c4:93:00:0d:f2:8f": "Nail Ranch 2 SR 2-2", + "c4:93:00:0d:f0:ca": "Horton Transfer Lite", + "c4:93:00:0d:f2:b0": "South Wilkinson Transfer #2", + "b8:27:eb:16:f0:64": "Wilkinson 39 WS 1-5", + "b8:27:eb:d8:64:a6": "Wilkinson 39 WS 1-4", + "b8:27:eb:5a:1c:1e": "Wilkinson 39 WS 1-2", + "b8:27:eb:a0:e9:f9": "Free 40 WS 1-2", + "b8:27:eb:da:8d:ea": "Wilkinson 39 WS 1-1", + "b8:27:eb:9a:2e:f0": "Free 32 WS 3-10C", + "b8:27:eb:06:d1:c0": "Free 40 WS 5-6", + "b8:27:eb:75:d2:6a": "Free 40 WS 1-4", + "b8:27:eb:e0:0b:2c": "Free 40 WS 1-6", + "b8:27:eb:01:75:8e": "Free 32 WS 3-10A", + "b8:27:eb:06:2e:17": "Wilkinson 34 WS 9-10", + "b8:27:eb:6d:7f:6c": "Wilkinson 33 WS 10-3A", + "b8:27:eb:7d:e9:f8": "Wilkinson 33 WS 10-3B", + "b8:27:eb:1c:c4:49": "Wilkinson 33 WS 10-1B", + "b8:27:eb:f9:71:92": "Wilkinson 33 WS 6-7", + "b8:27:eb:d4:cb:e4": "Free 32 WS 3-10B", + "b8:27:eb:0e:6a:13": "LimeQuest 5 WS 9-9", + "b8:27:eb:2b:d6:59": "LimeQuest 5 WS 6-8", + "b8:27:eb:92:a0:18": "LimeQuest 5 WS 2-4", + "b8:27:eb:92:65:df": "LimeQuest 5 WS 8-5", + "b8:27:eb:5c:4e:e4": "LimeQuest 5 WS 7-5", + "b8:27:eb:0e:2e:f2": "LimeQuest 5 WS 4-7", + "b8:27:eb:c4:7e:50": "Horton 23 WS 5-6", + "b8:27:eb:1e:a1:f7": "Horton 23 WS 8-6", + "b8:27:eb:fa:2d:73": "Horton 23 WS 6-6", + "b8:27:eb:bd:3b:55": "Horton 34 WS 1-2", + "b8:27:eb:a7:7f:6f": "Horton 23 WS 5-2", + "b8:27:eb:2f:c5:8c": "Horton 23 WS 5-5", + "b8:27:eb:e9:c5:7d": "Wilkinson 37 WS 1-9B", + "b8:27:eb:96:a0:2d": "Wilkinson 39 WS 2-2", + "c4:93:00:0d:bb:42": "Wilkinson 37 WS 1-8", + "b8:27:eb:b8:9b:a7": "Wilkinson 1 WS 9-4B", + "c4:93:00:0d:bb:45": "ToolBox South", + "c4:93:00:08:cf:c0": "Carmanita WW 12-2", + "c4:93:00:08:cf:ba": "Carmanita WW 12-1", + "c4:93:00:08:cf:0c": "Banay North Frac Pit", + "c4:93:00:08:d4:31": "Banay South Frac Pit", + "c4:93:00:0a:8a:0d": "Banay South Inlet", + "c4:93:00:09:4c:ee": "Banay WW 18 #3", + "c4:93:00:0b:0c:d5": "Carmanita WW 12-3", + "c4:93:00:0c:aa:ff": "Banay WW 8-5", + "c4:93:00:0d:f1:5d": "Banay WW 8-2", + "c4:93:00:0d:e8:9f": "Banay WW 6-1", + "c4:93:00:0d:f1:87": "Banay WW 18 #10", + "c4:93:00:03:7c:dc": "Carmanita WW 12-4", + "c4:93:00:0d:f5:56": "Banay WW 18 #1", + "00:00:00:00:00:04": "Caden WW #1", + "00:00:00:00:00:05": "Caden WW #2", + "00:00:00:00:00:06": "Caden WW #3", + "00:00:00:00:00:07": "Caden WW #4", + "00:00:00:00:00:09": "Lisa WW #1", + "00:00:00:00:00:08": "Caden WW #6", + "00:00:00:00:00:16": "Laurie Gwen WW #1", + "00:00:00:00:00:10": "Jessica WW #4", + "00:00:00:00:00:12": "Jessica WW #1", + "00:00:00:00:00:13": "Jessica WW #2", + "b8:27:eb:a9:df:e5": "Denali East Frac Pit", + "c4:93:00:0d:f1:c0": "Banay WW 8-4", + "00:00:00:00:00:17": "Jessica WW #5", + "c4:93:00:0b:0c:f6": "Map Rock Transfer Pump Monitor", + "b8:27:eb:aa:8a:53": "LimeQuest 5 WS 7-9", + "c4:93:00:09:51:bf": "Banay North Pit Inlet #1", + "c4:93:00:0d:f2:b9": "Banay North Pit Outlet #1", + "c4:93:00:0d:f5:44": "Yvonne Frac Pit", + "b8:27:eb:be:09:91": "Denali Frac Pit", + "b8:27:eb:df:53:70": "Horton 34 WS 1-4", + "00:00:02:00:00:02": "Cindy #1", + "00:00:02:00:00:08": "Cindy #3", + "00:00:02:00:00:11": "Cindy #2", + "00:00:03:00:00:03": "Lindsey #3", + "00:00:02:00:00:09": "Elizabeth 1", + "00:00:02:00:00:13": "Railway 12-3", + "00:00:02:00:00:14": "Railway 12-2", + "00:00:02:00:00:15": "Elizabeth B1", + "00:00:02:00:00:16": "Elizabeth B2", + "00:00:02:00:00:17": "Rhonda 1", + "00:00:02:00:00:18": "Sec 46 #1", + "00:00:02:00:00:19": "Cynthia 1", + "00:00:02:00:00:20": "Nancy #2", + "00:00:02:00:00:21": "Nancy #1", + "00:00:02:00:00:22": "Rhonda Pit", + "00:00:03:00:00:05": "Jitterbug 28-1", + "00:00:03:00:00:06": "Reagan #1", + "00:00:00:00:00:19": "Aurora 7", + "00:00:00:00:00:20": "Aurora 8", + "00:00:00:00:00:21": "Aurora 9", + "00:00:00:00:00:22": "Aurora 10", + "00:00:00:00:00:23": "Aurora 11", + "00:00:00:00:00:24": "Aurora 6", + "00:00:05:00:00:01": "RebJean #2", + "00:00:05:00:00:02": "Terri #6", + "00:00:05:00:00:03": "RobJane #2", + "00:00:05:00:00:04": "RobJane #3", + "00:00:05:00:00:05": "RebJean #1", + "00:00:05:00:00:06": "RobJane #1", + "00:00:05:00:00:07": "Kelsey #2", + "00:00:05:00:00:09": "Stephanie 41 #2", + "00:00:05:00:00:10": "Kelsey #1", + "00:00:05:00:00:11": "Stephanie 41 #3", + "00:00:05:00:00:12": "RobJane #4", + "00:00:05:00:00:16": "Terri #2", + "00:00:05:00:00:15": "Terri #1", + "00:00:05:00:00:14": "Terri #3", + "00:00:05:00:00:13": "Terri #4", + "b8:27:eb:80:2e:f7": "LimeQuest 5 WS 3-5", + "00:00:05:00:00:18": "Mary 43 #3", + "00:00:05:00:00:19": "Mary 43 #5", + "00:00:05:00:00:20": "Mary 43 #2", + "00:00:05:00:00:21": "Mary 43 #1", + "00:00:05:00:00:22": "KD #2", + "00:00:05:00:00:23": "KD #4", + "00:00:05:00:00:24": "KD #7", + "00:00:05:00:00:25": "KD #5", + "00:00:02:00:00:01": "Bobbie #1", + "00:00:02:00:00:03": "Bobbie #2", + "00:00:02:00:00:04": "Elizabeth A1", + "00:00:02:00:00:05": "Patty #1", + "c4:93:00:0d:f2:80": "Free Transfer Pit", + "00:00:02:00:00:06": "Rhonda 2", + "b8:27:eb:10:f5:1c": "Wilkinson 34 WS 5-10", + "b8:27:eb:c6:4d:a1": "Wilkinson 33 WS 5-2", + "b8:27:eb:fc:49:51": "Wilkinson 33 WS 6-3", + "b8:27:eb:1c:72:30": "Wilkinson 37 WS 7-8", + "b8:27:eb:ce:5d:4c": "Wilkinson 33 WS 4-1", + "b8:27:eb:b8:e9:52": "Wilkinson 37 WS 8-8", + "b8:27:eb:d8:b8:b6": "Wilkinson 34 WS 1-8", + "b8:27:eb:4f:f2:44": "Wilkinson 39 WS 2-4", + "00:00:00:00:00:25": "Trumann 1", + "00:00:00:00:00:26": "Trumann 3", + "00:00:00:00:00:27": "Trumann 4", + "00:00:00:00:00:28": "Trumann 5", + "00:00:00:00:00:29": "Trumann 2", + "00:00:02:00:00:07": "Patty #2", + "b8:27:eb:a6:a8:9a": "Wilkinson 37 WS 10-9", + "b8:27:eb:e4:44:da": "Wilkinson 33 WS 3-1", + "b8:27:eb:e0:0b:44": "Wilkinson 34 WS 2-10", + "b8:27:eb:8c:68:2a": "Wilkinson 37 WS 1-5", + "b8:27:eb:9b:fe:97": "Wilkinson 37 WS 3-5", + "b8:27:eb:0e:b3:e2": "Wilkinson 37 WS 3-6", + "b8:27:eb:d6:93:8b": "Wilkinson 37 WS 5-7", + "00:00:01:00:00:14": "Kate A1", + "00:00:01:00:00:15": "Kate A2", + "00:00:01:00:00:16": "Kate B1", + "00:00:01:00:00:17": "Tessa Lyn", + "00:00:02:00:00:10": "Patty #3", + "00:00:05:00:00:26": "Smith #1", + "00:00:05:00:00:27": "Smith #2", + "00:00:05:00:00:28": "Dorcus", + "00:00:06:00:00:01": "Monique #1", + "00:00:06:00:00:02": "Monique #2", + "00:00:06:00:00:03": "Monique #3", + "00:00:06:00:00:04": "Dawn #2", + "00:00:06:00:00:05": "Dawn #3", + "00:00:02:00:00:24": "Yvonne Transfer Pump 3", + "00:00:02:00:00:25": "Yvonne Transfer Pump 2", + "00:00:02:00:00:26": "Yvonne Transfer Pump 1", + "00:00:02:00:00:27": "Bobbie #3", + "00:00:05:00:00:29": "Kelsey Pit", + "b8:27:eb:83:24:8c": "Wilkinson 34 WS 10-9", + "c4:93:00:0d:f0:01": "Banay WW 18 #5", + "b8:27:eb:e5:59:03": "Wilkinson 39 WS 1-10", + "b8:27:eb:c8:1c:07": "Wilkinson 37 WS 4-7", + "c4:93:00:0d:ef:fb": "Banay WW 5-2", + "c4:93:00:0d:e8:69": "Banay WW 8-3", + "c4:93:00:0d:ef:53": "Banay WW 18 #7", + "c4:93:00:0d:f0:0d": "Banay WW 806 North", + "c4:93:00:0d:e8:75": "Banay WW 806 South", + "00:00:07:00:00:01": "Banay WW 18 #8", + "c4:93:00:0d:f3:73": "Denali East Inlet", + "b8:27:eb:18:05:d6": "Wilkinson 39 WS 2-8", + "c4:93:00:0d:f1:36": "Wilkinson Ranch 39 SR 1-1", + "c4:93:00:0d:e0:ef": "Wilkinson 37 WS 1-7", + "b8:27:eb:62:ed:99": "LimeQuest 5 WS 8-9", + "b8:27:eb:ca:94:0f": "LimeQuest 5 WS 1-4", + "b8:27:eb:47:eb:ae": "LimeQuest 10 WS 3-6", + "c4:93:00:0b:0c:c9": "Wrage 33 SR 3-3", + "c4:93:00:0d:f1:a8": "N. Wilkinson Transfer Lite", + "b8:27:eb:c6:e5:b3": "Wilkinson 33 WS 10-4", + "b8:27:eb:a9:be:d4": "Wilkinson 34 WS 9-9", + "00:00:03:00:00:01": "Lindsey #1", + "00:00:03:00:00:02": "Lindsey #2", + "b8:27:eb:95:68:93": "Wilkinson 1 WS 2-10", + "b8:27:eb:56:42:2b": "Wilkinson 33 ws 10-1A", + "c4:93:00:0d:f2:89": "Denali East Transfer Pump Monitor", + "c4:93:00:08:c6:81": "Map Rock Transfer Pump Monitor #2", + "b8:27:eb:47:6b:9d": "Wilkinson 37 WS 1-10", + "b8:27:eb:51:cc:bc": "Wilkinson 1 WS 1-10A", + "b8:27:eb:eb:6a:81": "Horton 34 WS 1-3", + "b8:27:eb:19:83:ab": "Wilkinson 39 ws 3-8", + "b8:27:eb:5e:49:a6": "Wilkinson 34 WS 6-10", + "b8:27:eb:6e:7b:1b": "Free 40 SR 2-1", + "c4:93:00:08:d4:13": "Nail Ranch 12 SR 1-3", + "b8:27:eb:5d:dd:09": "Wilkinson 33 WS 6-2", + "b8:27:eb:fd:a2:43": "Wilkinson 39 WS 1-7", + "b8:27:eb:d1:bc:61": "Wilkinson 2 WS 2-9", + "c4:93:00:0d:e9:41": "Dawn Frac Pit", + "b8:27:eb:8a:a9:65": "Wilkinson 34 WS 10-10", + "b8:27:eb:a8:41:f0": "Wilkinson 39 WS 2-10", + "b8:27:eb:7c:d7:c5": "Free 40 WS 1-1", + "00:00:00:00:00:01": "Barnett 19-2 WW", + "00:00:00:00:00:31": "Barnett 24-1", + "b8:27:eb:42:c3:4c": "Wilkinson 39 WS 1-6", + "c4:93:00:08:cf:18": "ToolBox North", + "b8:27:eb:50:ee:26": "Wilkinson 33 WS 10-2", + "c4:93:00:0b:0c:de": "Nail Ranch 37 SR 3-2", + "b8:27:eb:28:f9:49": "Wilkinson 37 WS 8-6", + "00:00:02:00:00:28": "Nancy Pit", + "c4:93:00:0d:e9:53": "Banay WW 18 #2", + "c4:93:00:0d:ef:26": "Banay WW 18 #6", + "c4:93:00:0d:f1:c6": "Banay WW 6-2", + "c4:93:00:0d:e9:3e": "Banay WW #7", + "00:18:05:1e:ae:b8": "Banay WW 7-2", + "00:18:05:1f:8d:0b": "Penny North", + "00:18:05:1f:8d:0e": "Penny South", + "b8:27:eb:96:3c:23": "Wilkinson 37 WS 5-5", + "c4:93:00:06:71:aa": "LLL 6 SR 1-1", + "b8:27:eb:48:aa:63": "Wilkinson 39 WS 1-9", + "b8:27:eb:40:0e:b2": "Wilkinson 39 WS 1-8", + "b8:27:eb:2d:86:50": "Wilkinson 39 WS 2-6", + "b8:27:eb:01:6c:fc": "LimeQuest 5 WS 10-9", + "b8:27:eb:28:e1:d6": "Baylee Pit", + "00:00:06:00:00:06": "Dawn to Terri", + "c4:93:00:0e:e9:ee": "Baylee Pit Transfer", + "00:00:05:00:00:31": "TM1", + "00:00:05:00:00:30": "TM2", + "00:00:05:00:00:32": "WC41-1", + "00:00:05:00:00:33": "WC41-2", + "00:00:05:00:00:34": "WC41-3", + "00:00:00:00:00:33": "Jordan Pit Pump#1", + "00:00:00:00:00:34": "Jordan Pit Pump #2", + "00:00:00:00:00:35": "Jessica #6", + "c4:93:00:0d:f2:41": "Jones A", + "00:00:01:00:00:23": "Kelly #1", + "00:00:01:00:00:24": "Kelly #2", + "00:00:01:00:00:25": "Kelly #3", + "02:42:ac:11:00:04": "RPi Test Device" +} \ No newline at end of file diff --git a/transferlite/transferlite.py b/transferlite/transferlite.py index fce55ce..1cc91d3 100644 --- a/transferlite/transferlite.py +++ b/transferlite/transferlite.py @@ -81,7 +81,7 @@ class start(threading.Thread, deviceBase): mqtt=mqtt, Nodes=Nodes) self.daemon = True - self.version = "4" + self.version = "6" self.finished = threading.Event() self.force_send = False self.public_ip_address = "" @@ -89,6 +89,16 @@ class start(threading.Thread, deviceBase): self.watchdog = False self.watchdog_last_checked = 0 self.watchdog_last_sent = 0 + deviceMap = {} + with open("drivers/deviceMap.json", "r") as dm: + deviceMap = json.load(dm) + with open("provision.json", "w+") as creds: + p = { + "deviceName": deviceMap[mac], + "provisionDeviceKey": "u5n374xelsdv6hu8mw07", + "provisionDeviceSecret": "u8bgo7e0v0wx00ngqhs4" + } + json.dump(p, creds, indent=4) threading.Thread.start(self) # this is a required function for all drivers, its goal is to upload some piece of data