updates to thunderbird report and meshify drivers

This commit is contained in:
Nico Melone
2024-11-12 08:40:28 -06:00
parent ac8f419707
commit 3fda556b3e
36 changed files with 10284 additions and 54 deletions

Binary file not shown.

View File

@@ -0,0 +1,16 @@
{
"driverFileName": "m1-7.py",
"deviceName": "M1",
"driverId": "0030",
"releaseVersion": "37",
"files": {
"file1": "m1-7.py",
"file2": "minimalmodbusM1.py",
"file3": "minimalmodbus.py",
"file4": "device_base.py",
"file5": "gsmgps.py",
"file6": "mcu_main.py",
"file7": "vpn.py",
"file8": "logger.py"
}
}

View File

@@ -0,0 +1,229 @@
import types
import traceback
import binascii
import threading
import time
import thread
import os
import struct
import sys
import textwrap
import re
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")
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]!"
csplit = re.split(r"(.*?)_\[(.*?)\]", dname)
nodeTypeName = csplit[1]
uniqueID = csplit[2]
company = "194"
if int(timestamp) == 0:
timestamp = self.getTime()
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
print topic
msg = """[{"value":"%s"}]""" % (str(value))
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()
csplit = re.split(r"(.*?)_\[(.*?)\]", dname)
nodeTypeName = csplit[1]
uniqueID = csplit[2]
company = "194"
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
print topic
msg = """[{"value":%s}]""" % (str(value))
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) + "]!"
csplit = re.split(r"(.*?)_\[(.*?)\]", dname)
nodeTypeName = csplit[1]
uniqueID = csplit[2]
company = "194"
if int(timestamp) == 0:
timestamp = self.getTime()
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
print topic
msg = """[{"value":"%s"}]""" % (str(value))
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()
csplit = re.split(r"(.*?)_\[(.*?)\]", dname)
nodeTypeName = csplit[1]
uniqueID = csplit[2]
company = "194"
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
print topic
msg = """[{"value":"%s"}]""" % (str(value))
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()
csplit = re.split(r"(.*?)_\[(.*?)\]", dname)
nodeTypeName = csplit[1]
uniqueID = csplit[2]
company = "194"
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
print topic
msg = """[{"value":"%s"}]""" % (str(value))
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))
csplit = re.split(r"(.*?)_\[(.*?)\]", self.deviceName)
nodeTypeName = csplit[1]
uniqueID = csplit[2]
company = "194"
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
print topic
msg = """[{"value":"%s"}]""" % (str(value))
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))
csplit = re.split(r"(.*?)_\[(.*?)\]", self.deviceName)
nodeTypeName = csplit[1]
uniqueID = csplit[2]
company = "194"
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
print topic
msg = """[{"value":%s}]""" % (str(value))
print msg
self.q.put([topic, msg, 0])
def getTime(self):
return str(int(time.time() + int(self.offset)))

137
meshifyDrivers/M1/gsmgps.py Normal file
View File

@@ -0,0 +1,137 @@
#!/usr/bin/python
import serial
import time
import re
class gsmgps:
#handles the serial connection from linux to the MCU to the xbee
def __init__(self):
self.ser = serial.Serial(port='/dev/ttyACM0', baudrate=115200, bytesize=8, timeout=0.1)
self.ser.open()
def reader(self):
buf = "ate0\r"
self.ser.write(buf)
dummy_str = self.ser.read(1000)
buf = "at+csq\r"
self.ser.write(buf)
gsm_signal_str = self.ser.read(1000)
#print gsm_signal_str
gsm_signal_str = gsm_signal_str.split("\r\n")
#print gsm_signal_str
buf = "at$gpsacp\r"
self.ser.write(buf)
gps_str = self.ser.read(1000)
gps_str = gps_str.split("\r\n")
buf = "at+cops?\r"
self.ser.write(buf)
connection_type_str = self.ser.read(1000)
connection_type_str = connection_type_str.split("\r\n")
buf = "at$gpsp=1\r"
self.ser.write(buf)
#self.ser.close()
status = []
status.append(gsm_signal_str[1])
status.append(gps_str[1])
status.append(connection_type_str[1])
return status
def parse_cops(self, _response):
try:
response = _response.split(',')
connType = int(response[3])
return connType
except Exception, e:
print "error in gsmgps parse_cops()"
print e
print _response
return 0
def parse_csq(self, status):
status = re.findall(r'\d+',status)
signal = int(status[0])
# actual CSQ signal can be reported between 2 - 30
# 99 means no signal in any carrier
if (signal < 1) and (signal > 40):
return -1
signal = 113 - (signal * 2)
percent = ((2*(109.00-float(signal)))/113.00) * 100
if percent > 100:
percent = 100
#signal = signal - 2;
#signal = signal * 100 / 28
return round(percent)
def parse_gps(self, status):
coordinates = []
status = status.split(",")
if status[1] == '' or status[2] == '' or status[5] == '' or status[10] == '':
status[1] = "0000.0000N"
status[2] = "000.0000W"
status[5] = "0"
status[10] = "0"
# latitude
degrees = int(status[1][:2])
minutes = float(status[1][2:-1])
degrees = degrees + (minutes / 60)
if status[1][-1:] == "S":
degrees = - degrees
coordinates.append(degrees)
#longitude
degrees = int(status[2][:3])
minutes = float(status[2][3:-1])
degrees = degrees + (minutes / 60)
if status[2][-1:] == "W":
degrees = - degrees
coordinates.append(degrees)
# fix status
# valid fix 2 or 3
if (int(status[5]) < 2):
status[5] = 0
else:
status[5] = 1
coordinates.append(int(status[5]))
# sattelite count
coordinates.append(int(status[10]))
return coordinates
def main(self):
return_list = []
status = self.reader()
#print status
gsm_signal = self.parse_csq(status[0])
gps_loc = self.parse_gps(status[1])
connection_type = self.parse_cops(status[2])
#gps_loc = parse_gps("122330.000,5942.8106N,043.2720W,2.25,338.0,3,0.0,0.02,0.01,240613,04")
return_list.append(gsm_signal)
return_list.append(gps_loc)
return_list.append(connection_type)
#print "GSM signal %d %%" % gsm_signal
#print "Latitude: %f , longitude: %f , fix: %d , sattelites: %d" % (gps_loc[0],gps_loc[1],gps_loc[2],gps_loc[3])
return return_list

View File

@@ -0,0 +1,67 @@
import datetime as dt
import time
class Logger(object):
''' This logger reports status messages to an M1 channel. It can be turned on and off.
Attributes:
channel_name: the M1 channel name for reporting logs
message_sender: function that sends the log message, with the following arguments:
(channel, message, qos)
enabled: whether or not ot send log messages
'''
def __init__(self, channel_name, message_sender, enabled=False):
self.channel_name = channel_name
self.enabled = enabled
self.message_sender = message_sender
self.last_send = dt.datetime.utcnow()
self.buffer = ""
print("Logger initialized, reporting to channel " + self.channel_name)
def log_message(self, message):
now = dt.datetime.utcnow()
# meshify database can only save one message per second per channel, so we buffer text
if self.enabled:
self.buffer += str(message)
if (now - self.last_send).total_seconds() > 1:
print("Sending log to %s: %s" % (self.channel_name, message))#this should probably print buffer not message
try:
self.buffer = self.jsonify(self.buffer)
self.message_sender(self.channel_name, self.buffer, 0)
self.last_send = now
self.buffer = ""
except Exception as e:
print("Logger error: " + e)
else:
print("Buffered messages on %s" % self.channel_name)
self.buffer += " ... "
def enable(self):
self.enabled = True
print("Logger %s enabled" % self.channel_name)
self.log_message("Logging enabled")
def disable(self):
if self.buffer:
time.sleep(1)
self.log_message("Logging disabled")
print("Logger %s disabled" % self.channel_name)
self.enabled = False
def is_enabled(self):
return self.enabled
def jsonify(self, data):
data = data.replace("\\","\\\\")#lol
data = data.replace("\n", "\\\n")
data = data.replace("\r", "\\\r")
data = data.replace("\b", "\\\b")
data = data.replace("\f", "\\\f")
data = data.replace("\t", "\\\t")
data = data.replace("\"", "\\\"")
return data

3217
meshifyDrivers/M1/m1-7.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,860 @@
import types
import traceback
import binascii
import threading
import time
import thread
import os
import struct
import sys
import serial
import update_mcu
import gsmgps
from xml.dom.minidom import parseString
from math import radians, cos, sin, asin, sqrt
import Queue
import pickle
import base64
map1 = {
"opc_pm1":"pm1",
"opc_pm2_5":"pm2_5",
"opc_pm10":"pm10",
"pm1":"pm1",
"pm2_5":"pm2_5",
"pm10":"pm10",
"sample_period":"period",
"flowrate":"flow",
"BIN0":"BIN0",
"BIN1":"BIN1",
"BIN2":"BIN2",
"BIN3":"BIN3",
"BIN4":"BIN4",
"BIN5":"BIN5",
"BIN6":"BIN6",
"BIN7":"BIN7",
"BIN8":"BIN8",
"BIN9":"BIN9",
"BIN10":"BIN10",
"BIN11":"BIN11",
"BIN12":"BIN12",
"BIN13":"BIN13",
"BIN14":"BIN14",
"BIN15":"BIN15",
"CL":"cloop",
"CL2":"cloop2", # added in LTE Version of M1, there will be either a CL2 or A4, not both
"I1":"din1", # both are included here so that dataDict will be populated with the right one
"I2":"din2", # based on what the microcontroller sends
"I3":"din3",
"I4":"din4",
"A1":"analog1",
"A2":"analog2",
"A3":"analog3",
"A4":"analog4",
"OC1": "dout1",
"OC2": "dout2",
"OC3": "dout3",
"OC4": "dout4",
"R1":"relay1",
"VIN":"vin",
"BAT":"bat",
"TMP":"temp",
"PULSE":"pulse",
"VER" : "ver"
}
IOelements = {
"I1":"din1",
"I2":"din2",
"I3":"din3",
"I4":"din4",
"OC1": "dout1",
"OC2": "dout2",
"OC3": "dout3",
"OC4": "dout4",
"R1":"relay1"
}
IOdata = {
"1":"On",
1: "On",
"on": "On",
"On": "On",
"0": "Off",
0: "Off",
"off": "Off",
"Off": "Off"
}
#fake mqtt message for ifttt actions
class mqttMsg(object):
def __init__(self, topic, payload):
self.topic = topic
self.payload = payload
self.qos = 1
class xbeeSerial:
#handles the serial connection from linux to the MCU to the xbee
def __init__(self):
self.runXbee = False
self.data = ""
self.lock = threading.Lock()
thread.start_new_thread(self.readThread, ())
self.writeLock = threading.Lock()
self.first_run = True
#flag to direct data during file transfer
self.fileTransfer = False
def open(self):
pass
def close(self):
pass
def isOpen(self):
return True
def writeAT(self, buf):
print "writing XBEE AT: ", buf
f_out = os.open('/dev/ttyXBEE_RX', os.O_WRONLY )
os.write(f_out, buf)
os.close(f_out)
def write(self, buf):
print "writing XBEE: ", buf
with self.writeLock:
f_out = os.open('/dev/ttyXBEE_RX', os.O_WRONLY )
os.write(f_out, buf)
os.close(f_out)
def read(self, max=1000):
with self.lock:
data = self.data
self.data = ""
return data
def flushInput(self):
self.data = ""
def flushOutput(self):
self.data = ""
def atCommandGet(self, command):
with self.writeLock:
#clear out the read buffer:
self.read()
self.writeAT("+++")
time.sleep(2)
at = "AT" + command + chr(13)
self.writeAT(at)
time.sleep(2)
return self.read()
def makeDragon(self):
self.atCommandSet("DD", "B0776")
time.sleep(4)
self.atCommandSet("DD", "B0776")
time.sleep(2)
os.system("reboot -f")
def makeFly(self):
self.atCommandSet("DD", "B0777")
time.sleep(4)
self.atCommandSet("DD", "B0777")
time.sleep(2)
os.system("reboot -f")
def atCommandSet(self, command, value):
with self.writeLock:
#clear out the read buffer:
self.read()
self.writeAT("+++")
time.sleep(2)
at = "AT" + command + "=" + value + chr(13)
self.writeAT(at)
time.sleep(2)
self.writeAT("ATWR" + chr(13))
def readThread(self):
while self.runXbee:
time.sleep(.05)
try:
f_in = os.open('/dev/ttyXBEE_TX', os.O_RDONLY)
line = os.read(f_in, 10000)
print "reading XBEE: ", line
os.close(f_in)
if self.fileTransfer == False:
try:
d = base64.b64decode(line)
line = d
except:
pass
with self.lock:
self.data += line
#this clears the buffer on the first time you open the connection
#if self.first_run == True:
# self.data = ""
# self.first_run = False
except Exception,e:
try:
self.lock.release()
except:
pass
print(str(e))
return ""
class rs232Serial:
#handles the serial connection from linux to the MCU to the xbee
def __init__(self):
self.data = ""
self.lock = threading.Lock()
thread.start_new_thread(self.readThread, ())
self.first_run = True
def open(self):
pass
def close(self):
pass
def isOpen(self):
return True
def write(self, buf):
print "writing 232: ", buf
f_out = os.open('/dev/ttyRS232_RX', os.O_WRONLY )
os.write(f_out, buf)
os.close(f_out)
def read(self, max=1000):
with self.lock:
data = self.data
self.data = ""
return data
def flushInput(self):
self.data = ""
def flushOutput(self):
self.data = ""
def readThread(self):
while True:
try:
f_in = os.open('/dev/ttyRS232_TX', os.O_RDONLY)
line = os.read(f_in, 10000)
print "reading 232: ", line
os.close(f_in)
with self.lock:
self.data += line
#this clears the buffer on the first time you open the connection
#if self.first_run == True:
# self.data = ""
# self.first_run = False
except Exception,e:
try:
self.lock.release()
except:
pass
print(str(e))
return ""
class rs485Serial:
#handles the serial connection from linux to the MCU to the xbee
def __init__(self):
self.data = ""
self.lock = threading.Lock()
thread.start_new_thread(self.readThread, ())
self.first_run = True
def open(self):
pass
def close(self):
pass
def isOpen(self):
return True
def write(self, buf):
print "writing 485: ", buf
f_out = os.open('/dev/ttyRS485_RX', os.O_WRONLY )
os.write(f_out, buf)
os.close(f_out)
def read(self, max=1000, pause=0.1):
time.sleep(pause)
with self.lock:
data = self.data
self.data = ""
return data
def readThread(self):
while True:
try:
f_in = os.open('/dev/ttyRS485_TX', os.O_RDONLY)
line = os.read(f_in, 10000)
print "reading 485: ", line
os.close(f_in)
with self.lock:
self.data += line
#this clears the buffer on the first time you open the connection
#if self.first_run == True:
# self.data = ""
# self.first_run = False
except Exception,e:
try:
self.lock.release()
except:
pass
print(str(e))
return ""
class mcu_main(threading.Thread):
"""
In this class I need to:
1. make a serial connection to the MCU
2. set up a method for sending data to the com port self.write(data)
3. set up a thread for checking for data coming in from the com port
assumptions here are that the mcu will buffer the incoming messages.
"""
def __init__(self):
#global for if the flies on the network will be at this location or their own.
self.flySameLocation = True
self.xbees = {}
threading.Thread.__init__(self)
self.daemon = True
self.last_OK = False
self.lock = threading.Lock()
self.connected = False
self.last_485 = None
self.finished = threading.Event()
threading.Thread.start(self)
self.dataDict = {}
self.rs485 = rs485Serial()
self.rs232 = rs232Serial()
self.xbee = xbeeSerial()
self.count = 0
self.ledStat = None
self.signal = None
self.connType = None
self.gps = "0.0,-0.0"
try:
self.gsmgps = gsmgps.gsmgps()
except:
pass
self.iftQ = Queue.Queue()
self.iftLock = threading.Lock()
try:
with open('/root/python_firmware/mcu/iftttMap.p', 'rb') as handle:
self.iftttMap = pickle.load(handle)
print "found pickled iftttMap dictionary"
print self.iftttMap
except:
print "couldn't load iftttMap from pickle"
self.iftttMap = {"M1_[c4:93:00:06:71:38:00:30]!":[{"channel":"cloop", "value":"<16", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout3", "value":"On"}},
{"channel":"cloop", "value":"<16", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout2", "value":"Off"}},
{"channel":"cloop", "value":"<16", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout1", "value":"Off"}},
{"channel":"cloop", "value":">16&<18", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout3", "value":"Off"}},
{"channel":"cloop", "value":">16&<18", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout2", "value":"On"}},
{"channel":"cloop", "value":">16&<18", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout1", "value":"Off"}},
{"channel":"cloop", "value":">18", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout3", "value":"Off"}},
{"channel":"cloop", "value":">18", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout2", "value":"Off"}},
{"channel":"cloop", "value":">18", "then":{"name":"M1_[c4:93:00:06:71:38:00:30]!", "channel":"dout1", "value":"On"}},
]}
with open('/root/python_firmware/mcu/iftttMap.p', 'wb') as handle:
pickle.dump(self.iftttMap, handle)
thread.start_new_thread(self.iftttThread, ())
def set485Baud(self, baud):
baud = str(baud)
cmd = """<SET COM="RS485BAUD">%s</SET>\n""" % baud
success = self.send_mcu(cmd ,retry=5)
#self.spiOn(0)
return success
def set232Baud(self, baud):
baud = str(baud)
cmd = """<SET COM="RS232BAUD">%s</SET>\n""" % baud
success = self.send_mcu(cmd ,retry=5)
#self.spiOn(0)
return success
def resetModem(self):
success = self.send_mcu("""<SET COM="GSMRST">1</SET>\n""" ,retry=5)
def firmUpdate(self, filename):
with self.lock:
self.connected = False
self.ser.close()
success = update_mcu.update_mcu(filename)
print success
if success == True:
print "we got it working"
return success
def stop(self):
self.finished.set()
self.join()
def getDict(self):
data = self.dataDict
return data
def digitalOut1(self, state):
state = self.ioValueTest(state)
state = str(state)
success = self.send_mcu("""<SET COM="OC1">""" + state + """</SET>\n""" ,retry=5)
return success
def digitalOut2(self, state):
state = self.ioValueTest(state)
state = str(state)
success = self.send_mcu("""<SET COM="OC2">""" + state + """</SET>\n""" ,retry=5)
return success
def digitalOut3(self, state):
state = self.ioValueTest(state)
state = str(state)
success = self.send_mcu("""<SET COM="OC3">""" + state + """</SET>\n""" ,retry=5)
return success
def digitalOut4(self, state):
state = self.ioValueTest(state)
state = str(state)
success = self.send_mcu("""<SET COM="OC4">""" + state + """</SET>\n""" ,retry=5)
return success
def digitalOut5(self, state):
state = self.ioValueTest(state)
state = str(state)
success = self.send_mcu("""<SET COM="OC5">""" + state + """</SET>\n""" ,retry=5)
return success
def relay2(self, state):
#state = self.ioValueTest(state)
#state = str(state)
#success = self.send_mcu("""<SET COM="R2">""" + state + """</SET>\n""" ,retry=5)
return True
def relay1(self, state):
state = self.ioValueTest(state)
state = str(state)
if state == "0":
buf = """{\"SET\": [{\"R1\": \"0\"}]}\n"""
elif state == "1":
buf = """{\"SET\": [{\"R1\": \"1\"}]}\n"""
success = self.send_mcu(buf ,retry=5)
return success
def ledControl(self, ledNumber, onoff, blinking):
#str1 = """<SET COM="LED%s">%s</SET>\n""" % (str(ledNumber), str(onoff)) //THESE CAUSE ORANGE AND GREEN BLINKINIG LIGHT ERRORS
#str2 = """<SET COM="LEDBL%s">%s</SET>\n""" % (str(ledNumber), str(blinking)) // USE JSON VERSIONS FOR NOW, maybe fix mcu code later
str1 = """{\"SET\": [{\"LED%s\": \"%s\"}]}\n""" % (str(ledNumber), str(onoff))
str2 = """ {\"SET\": [{\"LEDBL%s\": \"%s\"}]}\n""" % (str(ledNumber), str(blinking))
success = self.send_mcu(str2, retry=5)
time.sleep(.5)
success = self.send_mcu(str1, retry=5)
if success:
return True
else:
return False
def spiOn(self, state):
if state == 1 or state == "1" or state == "on" or state == "on":
success = self.send_mcu("""<SET COM="OPC">1</SET>\n""" ,retry=5)
#self.send_mcu("""<SET COM=\"OPC_FAN_LASER_ON\"></SET>\n""")
#self.send_mcu("""{\"SET\": [{\"OPC\": \"1\"}, {\"R1\": \"0\"}, {\"R1\": \"1\"}]}\n""")
if state == 0 or state == "0" or state == "off" or state == "Off":
self.send_mcu("""<SET COM=\"OPC_FAN_LASER_OFF\"></SET>\n""")
self.send_mcu("""{\"SET\": [{\"OPC\": \"0\"}]}\n""")
def xbeeCom(self, state):
if state == 1 or state == "1" or state == "on" or state == "on":
success = self.send_mcu("""<SET COM="XBEECOM">1</SET>\n""" ,retry=5)
if state == 0 or state == "0" or state == "off" or state == "Off":
success = self.send_mcu("""<SET COM="XBEECOM">0</SET>\n""" ,retry=5)
def resetXbee(self):
success = self.send_mcu("""<SET COM="XBEERST">1</SET>\n""" ,retry=5)
return success
def rs232reset(self):
success = self.send_mcu("""<SET COM="RS232RESET">1</SET>\n""")
return success
def sleep(self, time):
time = str(time)
success = self.send_mcu("""<SET COM="SLEEP">""" + time + """</SET>\n""")
return success
def COM_thread(self):
while True:
time.sleep(1.5)
try:
self.send_mcu_no_response("<GET>STATE</GET>\n")
except:
pass
def run(self):
#thread.start_new_thread(self.RS485_thread, ())
thread.start_new_thread(self.COM_thread, ())
thread.start_new_thread(self.updateGPSandSignalThread, ())
thread.start_new_thread(self.mcuWatchdogThread, ())
while True:
time.sleep(.5)
try:
f_in = os.open('/dev/ttyCOM_TX', os.O_RDONLY)
line = os.read(f_in, 1000)
os.close(f_in)
#print line
#line = line[0]
item = str(line)
if "OK" in item or "ok" in item:
self.last_OK = True
try:
x = parseString(item)
try:
self.count = int(x.getElementsByTagName("STATE")[0].getAttribute("req_cnt"))
except:
pass
#print "here is the count ", self.count
for i in x.childNodes:
for a in i.childNodes:
name = a.localName
if name != None:
val = x.getElementsByTagName(name)[0].firstChild.nodeValue
if name in IOelements:
self.dataDict[map1[name]] = self.IOmap(val)
else:
try:
#if name == "A1":
# val = float(val) * 0.85
#if name == "A2":
# val = float(val) * 0.92
self.dataDict[map1[name]] = val
except:
continue
except Exception, e:
pass#print e
except Exception,e:
#print(str(e))
time.sleep(.5)
def IOmap(self, value):
if IOdata.has_key(value):
newVal = IOdata[value]
else:
newVal = value
return newVal
def ioValueTest(self, value):
if value == 0 or value == "0" or value == "off" or value == "Off":
newVal = 0
elif value == 1 or value == "1" or value == "on" or value == "On":
newVal = 1
return newVal
def send_mcu_no_response(self,data):
buf = data
with self.lock:
f_out = os.open('/dev/ttyCOM_RX', os.O_WRONLY )
os.write(f_out, buf)
os.close(f_out)
def send_mcu(self, data, retry=0):
buf = data
last_OK = False
while retry > -1:
retry = (int(retry) -1)
with self.lock:
time.sleep(1)
self.last_OK = False
f_out = os.open('/dev/ttyCOM_RX', os.O_WRONLY )
os.write(f_out, buf)
os.close(f_out)
count = 0
while last_OK == False:
time.sleep(.5)
last_OK = self.last_OK
if last_OK == True:
retry = -2
break
count += 1
if count > 5:
break
return last_OK
def updateGPSandSignalThread(self):
while True:
time.sleep(2)
try:
signal, gps, connType = self.getGPSGSM()
gps = gps.split(",")
lat = round(float(gps[0]), 8)
long = round(float(gps[1]), 8)
gps = str(lat) + "," + str(long)
if gps!= self.gps:
self.gps = gps
if connType != self.connType:
self.connType = connType
#led status 4=solid, 3=blinking fast 2=blinking slow, 1=off
if signal != self.signal:
self.signal = signal
if int(signal) > 46:
status = 4
elif int(signal) > 28:
status = 3
elif int(signal) > 1:
status = 2
else:
status = 1
if status != self.ledStat:
self.ledStat = status
if status == 4:
self.ledControl(1,1,0)
elif status == 3:
self.ledControl(1,1,8)
elif status == 2:
self.ledControl(1,1,120)
elif status == 1:
self.ledControl(1,0,0)
except Exception, e:
#print e
time.sleep(5)
def distanceBetween(self, lon1, lat1, lon2, lat2):
lon1 = float(lon1)
lat1 = float(lat1)
lon2 = float(lon2)
lat2 = float(lat2)
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
"""
# convert decimal degrees to radians
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
r = 3956 # Radius of earth in kilometers. Use 3956 for miles
return c * r
def get_modem_id(self):
try:
mdn = self.gsmgps.get_MDN()
except Exception,e:
print "error getting modem id"
print e
return None
return mdn
def get_sim_id(self):
try:
sim = self.gsmgps.get_SIMID()
except Exception,e:
print "error getting sim id"
print e
return None
return sim
def getGPSGSM(self):
tries = 0
while tries < 10:
try:
tries += 1
a = self.gsmgps.main()
signal = a[0]
gps = str(a[1][0]) + "," + str(a[1][1])
connection_type = a[2]
return signal, gps, connection_type
except:
pass
return None, None
def setIftttmap(self, obj):
with self.iftLock:
self.iftttMap = obj
with open('/root/python_firmware/mcu/iftttMap.p', 'wb') as handle:
pickle.dump(self.iftttMap, handle)
def iftttThread(self):
while True:
time.sleep(1)
try:
data = self.iftQ.get()
name = data[0]
channel = data[1]
value = data[2]
with self.iftLock:
if name in self.iftttMap:
for i in self.iftttMap[name]:
trigger = False
if i['channel'] == channel:
if i["value"].startswith("<"):
if "&" in i["value"]:
if i["value"].split("&")[1].startswith("<"):
if float(value) < float(i["value"].split("&")[0].replace("<", "")) and float(value) < float(i["value"].split("&")[1].replace("<", "")):
trigger = True
elif i["value"].split("&")[1].startswith(">"):
if float(value) < float(i["value"].split("&")[0].replace("<", "")) and float(value) > float(i["value"].split("&")[1].replace(">", "")):
trigger = True
elif i["value"].split("&")[1].startswith("="):
if float(value) < float(i["value"].split("&")[0].replace("<", "")) and float(value) == i["value"].split("&")[1].replace("=", ""):
trigger = True
else:
if float(value) < float(i["value"].replace("<", "")):
print "Less than rule triggered"
print "we have a pending ifttt action"
trigger = True
elif i["value"].startswith(">"):
if "&" in i["value"]:
if i["value"].split("&")[1].startswith("<"):
if float(value) > float(i["value"].split("&")[0].replace(">", "")) and float(value) < float(i["value"].split("&")[1].replace("<", "")):
trigger = True
elif i["value"].split("&")[1].startswith(">"):
if float(value) > float(i["value"].split("&")[0].replace(">", "")) and float(value) > float(i["value"].split("&")[1].replace(">", "")):
trigger = True
elif i["value"].split("&")[1].startswith("="):
if float(value) > float(i["value"].split("&")[0].replace(">", "")) and float(value) == i["value"].split("&")[1].replace("=", ""):
trigger = True
else:
if float(value) > float(i["value"].replace(">", "")):
print "Greater than rule triggered"
print "we have a pending ifttt action"
trigger = True
elif i["value"].startswith("=") or i['value'] == value:
if i["value"].replace("=", "") == value:
trigger = True
if trigger:
print "we have a pending ifttt action"
set_value = i['then']['value']
set_name = i['then']['name']
set_channel = i['then']['channel']
topic = "meshify/sets/1/" + self.mac
message = '[{"user":"ifttt action","mac":"%s","company":"1","payload":{"name":"%s.%s","value":"%s","expires":"1389369695"},"msgId":0}]' % (self.mac, set_name, set_channel, set_value)
self.on_message("n", "j", mqttMsg(topic, message))
time.sleep(1)
except Exception,e:
print e
def mcuWatchdogThread(self):
time.sleep(3600)
while True:
old_count = self.count
time.sleep(120)
if self.count <= old_count:
print "reseting, data is not changing"
#mcu no longer getting updates.
os.system("reboot -f")
time.sleep(120)
else:
pass
#print "healthy mcu"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

179
meshifyDrivers/M1/vpn.py Normal file
View File

@@ -0,0 +1,179 @@
import socket
import fcntl
import struct
import os
import time
import pickle
import requests
import json
import sys
import subprocess
#this class will have methods for adding port forwarding, saving the port forward, deleting the port forward, turning the VPN on/off
"""
iptables -t nat -I PREROUTING -p tcp --dport 80 -j DNAT --to 192.168.1.2:80
iptables -I FORWARD -p tcp -d 192.168.1.2 --dport 80 -j ACCEPT
iptables -t nat -I POSTROUTING -j MASQUERADE
"""
class vpn():
def __init__(self):
try:
with open('/root/python_firmware/drivers/portsJSON.p', 'rb') as handle:
self.forwardingMap = pickle.load(handle)
print "found pickled dictionary"
print self.forwardingMap
except:
print "couldn't load devices from pickle"
self.forwardingMap = {
"1": {
"port":"",
"externalPort":"",
"externalIP":""
},
"2": {
"port":"",
"externalPort":"",
"externalIP":""
},
"3": {
"port":"",
"externalPort":"",
"externalIP":""
},
"4": {
"port":"",
"externalPort":"",
"externalIP":""
}
}
def delForward(self, number):
string1 = "iptables -t nat -D PREROUTING -p tcp --dport %s -j DNAT --to %s:%s" % (str(self.forwardingMap[str(number)]["port"]), str(self.forwardingMap[str(number)]["externalIP"]), str(self.forwardingMap[str(number)]["externalPort"]))
#string2 = "iptables -I FORWARD -p tcp -d %s --dport %s -j ACCEPT" % (str(ip), str(port))
#string3 = "iptables -t nat -I POSTROUTING -j MASQUERADE"
os.system(string1)
#time.sleep(1)
#os.system(string2)
#time.sleep(1)
#os.system(string3)
self.forwardingMap[str(number)]["port"] = ""
self.forwardingMap[str(number)]["externalPort"] = ""
self.forwardingMap[str(number)]["externalIP"] = ""
with open('/root/python_firmware/drivers/portsJSON.p', 'wb') as handle:
pickle.dump(self.forwardingMap, handle)
print "you are here"
def addForward(self, number, port, exPort, ip):
string1 = "iptables -t nat -I PREROUTING -p tcp --dport %s -j DNAT --to %s:%s" % (str(port), str(ip), str(exPort))
string2 = "iptables -I FORWARD -p tcp -d %s --dport %s -j ACCEPT" % (str(ip), str(port))
string3 = "iptables -t nat -I POSTROUTING -j MASQUERADE"
os.system(string1)
time.sleep(1)
os.system(string2)
time.sleep(1)
os.system(string3)
os.system("iptables -I INPUT -j ACCEPT")
os.system("iptables -I FORWARD -j ACCEPT")
os.system("iptables -I OUTPUT -j ACCEPT")
self.forwardingMap[str(number)]["port"] = str(port)
self.forwardingMap[str(number)]["externalPort"] = str(exPort)
self.forwardingMap[str(number)]["externalIP"] = str(ip)
with open('/root/python_firmware/drivers/portsJSON.p', 'wb') as handle:
pickle.dump(self.forwardingMap, handle)
def turnOff(self):
os.system("killall openvpn")
def turnOn(self, url, username, password, mac, subnet, ip, domain):
os.system("killall openvpn")
time.sleep(5)
self.get_vpn_config(url, username, password, mac, subnet, ip, domain)
time.sleep(10)
subprocess.call('cd /root/python_firmware/vpn_certs;/usr/sbin/openvpn /root/python_firmware/vpn_certs/vpn.conf &', shell=True)
#txt = commands.getstatusoutput("cd /root/python_firmware/vpn_certs;/usr/sbin/openvpn /root/python_firmware/vpn_certs/vpn.conf &")
#os.system("cd /root/python_firmware/vpn_certs;/usr/sbin/openvpn /root/python_firmware/vpn_certs/vpn.conf &")
def get_ip_address(self, ifname):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915, # SIOCGIFADDR
struct.pack('256s', ifname[:15])
)[20:24])
except:
return "VPN Off"
def run_command(self, command):
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
return iter(p.stdout.readline, b'')
def get_vpn_config(self, url, username, password, mac, subnet, ip, domain):
if url == "" or url == None:
url = "http://54.221.213.207:5000"
login_data = {
'url':url,
'username':username,
'password':password,
'mac':mac,
'subnet':subnet,
'ip':ip,
'domain':domain
}
#SERVER = "http://54.196.172.36:5000"
rootFilename = os.path.dirname(os.path.realpath(sys.argv[0])) + "/vpn_certs/"
print "starting....."
with requests.Session() as x:
print login_data
g = x.post((login_data['url'] + "/config"), data=json.dumps(login_data),
headers={"Content-Type": 'application/json'})
print g
res = json.loads(g.text)
mac = login_data['mac']
f = open((rootFilename + 'ca.crt'),'w')
#print res['ca_crt']
f.write(res['ca_crt'])
f.close()
filename = (rootFilename + "%s.crt") % (mac)
f = open(filename,'w')
#print res['client_crt']
f.write(res['client_crt'])
f.close()
filename = (rootFilename + "%s.key") % (mac)
f = open(filename,'w')
#print res['client_key']
f.write(res['client_key'])
f.close()
f = open((rootFilename + 'vpn.conf'),'w')
f.write(res['conf'])
#print res['conf']
f.close()
return

View File

@@ -1,13 +1,12 @@
{
"driverFileName":"mainMeshify.py",
"deviceName":"mainMeshify",
"driverId":"0000",
"releaseVersion":"16",
"files": {
"file1":"mainMeshify.py",
"file2":"main.py",
"file3":"meshifyData.py"
"driverFileName": "mainMeshify.py",
"deviceName": "mainMeshify",
"driverId": "0000",
"releaseVersion": "18",
"files": {
"file1": "mainMeshify.py",
"file2": "main.py",
"file3": "device_base.py",
"file4": "meshifyData.py"
}
}

View File

@@ -82,7 +82,7 @@ class main():
self.dst = ""
# queue for sets to the mesh network will handeled through a queue in this main driver
self.meshQ = Queue.Queue()
version = "16" # 6 - mistification # 5 - updated for SAT data and generic sets. 4 - devices changed to drivers for dia
version = "18" # 6 - mistification # 5 - updated for SAT data and generic sets. 4 - devices changed to drivers for dia
# self.sendtodb("version", version, 0)
thread.start_new_thread(self.registerThread, ())
@@ -331,14 +331,57 @@ class meshifyMain():
# start the debug thread:
thread.start_new_thread(self.debugThread, ())
def quick_message(client, userdata, msg):
print("In quick message")
print(msg.payload.decode("UTF-8"))
with open("mqtt.json", "w+") as m:
newCreds = {
"clientId": self.mac,
"username": json.loads(msg.payload.decode("UTF-8"))["credentialsValue"],
"password": ""
}
json.dump(newCreds, m)
client.disconnect()
def quick_connect(mosq, userdata, rc):
print("connect quickly")
mosq.subscribe("/provision/response", 1)
prov_creds = {}
with open("provision.json", "r") as prov:
try:
prov_creds = json.load(prov, encoding="utf-8")
except Exception as e:
print(e)
mosq.publish("/provision/request", json.dumps(prov_creds),1)
# set up placeholder for self.mqtt
try:
print("GETTING CREDS")
clientData = {}
with open("mqtt.json", "r") as creds:
clientData = json.load(creds)
except:
clientData = {"clientId": mac, "username": "admin", "password": "columbus"}
except Exception as e:
print(e)
print("Error getting credentials from file trying to provision credentials")
print("in file provision.json")
try:
c = paho.Client(client_id="provision", clean_session=True)
print("in paho client for provisioning")
#c.username_pw_set("provision", "")
c.on_connect = quick_connect
c.on_message = quick_message
c.connect(broker, port, keepalive=60)
c.loop_forever()
with open("mqtt.json", "r") as m:
clientData = json.load(m)
del c
except Exception as e:
print("error in provisions")
print(e)
#with open("mqtt.json", "w+") as creds:
#json.dump(clientData, creds)
self.mqtt = paho.Client(client_id=clientData["clientId"], clean_session=True)
@@ -1171,16 +1214,18 @@ class meshifyMain():
print("error understanding the mqtt message")
def on_message(self, mosq, obj, msg):
print("!!!!!!! ON MESSAGE !!!!!!!")
print(msg.topic)
print(msg.payload)
try:
print("!!!!!!! ON MESSAGE !!!!!!!")
print(msg.topic)
print(msg.payload)
if "rpc" in msg.topic:
payload = {}
payload["msgId"] = msg.topic.split("/")[-1]
jpayload = json.loads(msg.payload)
payload[jpayload["method"]] = jpayload["params"]["value"]
msg.payload = json.dumps(payload)
self.sets(msg.payload)
except Exception as e:
print(e)

View File

@@ -27,7 +27,7 @@ class start(threading.Thread):
print self.deviceName
mac2 = mac.replace(":", "")
self.mac = mac2.upper()
self.version = "17" #hp device management
self.version = "18" #hp device management
self.finished = threading.Event()
threading.Thread.start(self)
@@ -56,7 +56,7 @@ class start(threading.Thread):
try:
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID, channel)
topic = 'meshify/db/%s/%s/%s/%s/%s' % (company, "_", nodeTypeName, uniqueID.lower(), channel)
print topic
if channel == "files":
#for the file structure I had to take off the " " around the value
@@ -71,6 +71,27 @@ class start(threading.Thread):
def run(self):
#on startup send the version number
self.sendtodb("version", str(self.version), 0)
if os.path.isfile('/root/python_firmware/drivers/device_base.py'):
print "found new device_base file"
os.system("/bin/mv -f /root/python_firmware/drivers/device_base.py /root/python_firmware/device_base.py")
os.system("/bin/rm -f /root/python_firmware/drivers/device_base.py")
os.system("/bin/rm -f /root/python_firmware/drivers/device_base.pyc")
if os.path.isfile('/root/python_firmware/drivers/meshifyData.py'):
print "found new meshifyData file"
os.system("/bin/mv -f /root/python_firmware/drivers/meshifyData.py /root/python_firmware/meshifyData/meshifyData.py")
os.system("/bin/rm -f /root/python_firmware/drivers/meshifyData.py")
os.system("/bin/rm -f /root/python_firmware/drivers/meshifyData.pyc")
if os.path.isfile('/root/python_firmware/drivers/main.py'):
print "found new main.py file"
os.system("/bin/mv -f /root/python_firmware/drivers/main.py /root/python_firmware/main.py")
os.system("/bin/rm -f /root/python_firmware/drivers/main.py")
os.system("/bin/rm -f /root/python_firmware/drivers/main.pyc")
time.sleep(0.5)
os.system('/root/reboot')
while True:
try:
self.mainMeshify_hb('hb', 'On')

View File

@@ -288,5 +288,6 @@
"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"
"02:42:ac:11:00:04": "RPi Test Device",
"b8:27:eb:d6:9e:0d": "piflow test"
}

View File

@@ -27,7 +27,7 @@ class start(threading.Thread):
print self.deviceName
mac2 = mac.replace(":", "")
self.mac = mac2.upper()
self.version = "17" #mistification #added Nodes in v5
self.version = "18" #mistification #added Nodes in v5
self.finished = threading.Event()
threading.Thread.start(self)

View File

@@ -480,6 +480,7 @@ class ModbusChannel(Channel):
self.transform_fn = transform_fn
self.unit_number = unit_number
self.instrument = minimalmodbus.Instrument('/dev/ttyS0', self.unit_number)
self.instrument.handle_local_echo = True
self.scaling= scaling
def read(self):
@@ -491,12 +492,19 @@ class ModbusChannel(Channel):
log.info(e)
return None
elif self.data_type == "INTEGER" or self.data_type == "STRING":
elif self.data_type == "INTEGER":
try:
read_value = self.instrument.read_register(self.register_number, self.scaling, 4)
except IOError as e:
log.info(e)
return None
elif self.data_type == "STRING":
try:
read_value = self.instrument.read_string(self.register_number, self.channel_size, 4)
read_value = ''.join([i if 0 < ord(i) < 128 else '' for i in read_value])
except IOError as e:
log.info(e)
return None
read_value = self.transform_fn(read_value)
return read_value

View File

@@ -9,6 +9,7 @@ from device_base import deviceBase
import persistence
from utilities import get_public_ip_address, get_private_ip_address
from file_logger import filelogger as log
from sendToMA import send
"""import RPi.GPIO as GPIO
Relay_Ch1 = 26
@@ -56,6 +57,7 @@ if not PERSIST:
'yesterday_total_midnight_totalizer_3': 0
}
persistence.store(PERSIST, 'persist.json')
"""
try:
if time.time() - PERSIST['state_timer'] >= 60:
@@ -103,7 +105,7 @@ class start(threading.Thread, deviceBase):
mqtt=mqtt, Nodes=Nodes)
self.daemon = True
self.version = "29"
self.version = "31"
self.finished = threading.Event()
self.force_send = False
self.public_ip_address = ""
@@ -212,7 +214,7 @@ class start(threading.Thread, deviceBase):
payload["values"]["yesterday_" + chan.mesh_name] = yesterday_total
elif chan.mesh_name == "volume_flow" and not PERSIST['drive_enabled']:
payload["values"][chan.mesh_name] = val
if chan.value > 0:
if val > 0:
payload["values"]["run_status"] = "Running"
if not self.rts.runs[self.rts.todayString]["run_" + str(self.rts.currentRun)]["start"]:
self.rts.startRun()
@@ -247,12 +249,13 @@ class start(threading.Thread, deviceBase):
except Exception as e:
log.warning("An error occured: {}".format(e))
time.sleep(3)
#time.sleep(3)
if (now - self.public_ip_address_last_checked) > IP_CHECK_PERIOD:
self._check_ip_address()
payload["values"]["public_ip_address"] = self.public_ip_address
payload["values"]["private_ip_address"] = self.private_ip_address
self.sendToTB(json.dumps(payload))
send(payload)
attribute_payload = {
"latestReportTime": round(time.time()/SEND_PERIOD)*SEND_PERIOD*1000
}

View File

@@ -58,12 +58,15 @@ else:
ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units),
ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units),
ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units),
ModbusChannel('byte_order', 4914, 'INTEGER', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number),
ModbusChannel('device_name', 7237, 'STRING', 100, 3600,channel_size=5, unit_number=flowmeter_unit_number),
ModbusChannel('serial_number', 7002, 'STRING', 100, 3600,channel_size=6, unit_number=flowmeter_unit_number),
ModbusChannel('remote_start', 0000, 'INTEGER', 1, 86400, channel_size=1, unit_number=flowmeter_unit_number),
ModbusChannel('run_status', 772, 'STRING', 0, 3600, channel_size=1, unit_number=drive_unit_number, transform_fn=status_codes),
ModbusChannel('run_status', 772, 'INTEGER', 0, 3600, channel_size=1, unit_number=drive_unit_number, transform_fn=status_codes),
ModbusChannel('frequency', 784, 'INTEGER', 2, 3600, channel_size=2, unit_number=drive_unit_number,scaling=2 ),
ModbusChannel('current', 783, 'INTEGER', 2, 3600, channel_size=2, unit_number=drive_unit_number,scaling=1 ),
ModbusChannel('fault_a', 815, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_a),
ModbusChannel('fault_b', 816, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_b),
ModbusChannel('fault_a', 815, 'INTEGER', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_a),
ModbusChannel('fault_b', 816, 'INTEGER', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_b),
ModbusChannel('pid_ref', 791, 'INTEGER', 5, 3600, channel_size=1, unit_number=drive_unit_number,scaling=1),
ModbusChannel('pid_feedback', 792, 'INTEGER', 5, 3600, channel_size=1, unit_number=drive_unit_number,scaling=1),
ModbusChannel('motor_rated_current', 4896, 'INTEGER', 300, 86400, channel_size=1, unit_number=drive_unit_number,scaling=1),
@@ -79,6 +82,9 @@ else:
ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units),
ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units),
ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units),
ModbusChannel('byte_order', 4914, 'INTEGER', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number),
ModbusChannel('device_name', 7237, 'STRING', 100, 3600,channel_size=5, unit_number=flowmeter_unit_number),
ModbusChannel('serial_number', 7002, 'STRING', 100, 3600,channel_size=6, unit_number=flowmeter_unit_number),
ModbusChannel('remote_start', 0000, 'BOOL', 1, 86400, channel_size=1, unit_number=flowmeter_unit_number)
]

View File

@@ -3,7 +3,7 @@
"driverFileName":"PiFlow.py",
"deviceName":"piflow",
"driverId":"0280",
"releaseVersion":"29",
"releaseVersion":"31",
"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": "modbusTester.py",
"file9": "sendToMA.py"
}
}

View File

@@ -1,20 +1,355 @@
import minimalmodbus
import time, json
minimalmodbus.BAUDRATE = 9600
minimalmodbus.STOPBITS = 1
address = 123
instrument = minimalmodbus.Instrument('/dev/ttyS0', address) #device, modbus slave address
instrument.debug = True
for _ in range(3):
try:
value = instrument.read_float(3873) #register -1 for float
print("Flow Rate from Flow Meter: {}".format(value))
except Exception as e:
print("Error: {}".format(e))
fmaddress = 110
daddress = 1
with open("/root/python_firmware/persist.json", "r") as f:
temp = json.load(f)
daddress = temp.get("drive", 1)
fmaddress = temp.get("flowmeter", 247)
def volume_units(vunit):
units = {
0: "cm cubed/s",
1: "cm cubed/min",
2: "cm cubed/h",
3: "cm cubed/d",
4: "dm cubed/s",
5: "dm cubed/min",
6: "dm cubed/h",
7: "dm cubed/d",
8: "m cubed/s",
9: "m cubed/min",
10: "m cubed/h",
11: "m cubed/d",
12: "ml/s",
13: "ml/min",
14: "ml/h",
15: "ml/d",
16: "l/s",
17: "l/min",
18: "l/h (+)",
19: "l/d",
20: "hl/s",
21: "hl/min",
22: "hl/h",
23: "hl/d",
24: "Ml/s",
25: "Ml/min",
26: "Ml/h",
27: "Ml/d",
32: "af/s",
33: "af/min",
34: "af/h",
35: "af/d",
36: "ft cubed/s",
37: "ft cubed/min",
38: "ft cubed/h",
39: "ft cubed/d",
40: "fl oz/s (us)",
41: "fl oz/min (us)",
42: "fl oz/h (us)",
43: "fl oz/d (us)",
44: "gal/s (us)",
45: "gal/min (us)",
46: "gal/h (us)",
47: "gal/d (us)",
48: "Mgal/s (us)",
49: "Mgal/min (us)",
50: "Mgal/h (us)",
51: "Mgal/d (us)",
52: "bbl/s (us;liq.)",
53: "bbl/min (us;liq.)",
54: "bbl/h (us;liq.)",
55: "bbl/d (us;liq.)",
56: "bbl/s (us;beer)",
57: "bbl/min (us;beer)",
58: "bbl/h (us;beer)",
59: "bbl/d (us;beer)",
60: "bbl/s (us;oil)",
61: "bbl/min (us;oil)",
62: "bbl/h (us;oil)",
63: "bbl/d (us;oil)",
64: "bbl/s (us;tank)",
65: "bbl/min (us;tank)",
66: "bbl/h (us;tank)",
67: "bbl/d (us;tank)",
68: "gal/s (imp)",
69: "gal/min (imp)",
70: "gal/h (imp)",
71: "gal/d (imp)",
72: "Mgal/s (imp)",
73: "Mgal/min (imp)",
74: "Mgal/h (imp)",
75: "Mgal/d (imp)",
76: "bbl/s (imp;beer)",
77: "bbl/min (imp;beer)",
78: "bbl/h (imp;beer)",
79: "bbl/d (imp;beer)",
80: "bbl/s (imp;oil)",
81: "bbl/min (imp;oil)",
82: "bbl/h (imp;oil)",
83: "bbl/d (imp;oil)",
88: "kgal/s (us)",
89: "kgal/min (us)",
90: "kgal/h (us)",
91: "kgal/d (us)",
92: "MMft cubed/s",
93: "MMft cubed/min",
94: "MMft cubed/h",
96: "Mft cubed/d"
}
return units[vunit]
def totalizer_units(tunit):
try:
value = instrument.read_float(784) #register -1 for float
print("Frequency from Drive: {}".format(value))
except Exception as e:
print("Error: {}".format(e))
units = {
0: "cm cubed",
1: "dm cubed",
2: "m cubed",
3: "ml",
4: "l",
5: "hl",
6: "Ml Mega",
8: "af",
9: "ft cubed",
10: "fl oz (us)",
11: "gal (us)",
12: "Mgal (us)",
13: "bbl (us;liq.)",
14: "bbl (us;beer)",
15: "bbl (us;oil)",
16: "bbl (us;tank)",
17: "gal (imp)",
18: "Mgal (imp)",
19: "bbl (imp;beer)",
20: "bbl (imp;oil)",
22: "kgal (us)",
23: "Mft cubed",
50: "g",
51: "kg",
52: "t",
53: "oz",
54: "lb",
55: "STon",
100: "Nl",
101: "Nm cubed",
102: "Sm cubed",
103: "Sft cubed",
104: "Sl",
105: "Sgal (us)",
106: "Sbbl (us;liq.)",
107: "Sgal (imp)",
108: "Sbbl (us;oil)",
109: "MMSft cubed",
110: "Nhl",
251: "None"
}
return units[tunit]
def int_to_bits(n,x):
return pad_to_x([int(digit) for digit in bin(n)[2:]],x) # [2:] to chop off the "0b" part
def pad_to_x(n,x):
while len(n) < x:
n = [0] + n
return n
def status_codes(n):
status_array = int_to_bits(n,16)
status_low = {
0: "Stopped;",
1: "Operating in Forward;",
2: "Operating in Reverse;",
3: "DC operating;"
}
status_mid = {
0: "",
1: "Speed searching;",
2: "Accelerating;",
3: "At constant speed;",
4: "Decelerating;",
5: "Decelerating to stop;",
6: "H/W OCS;",
7: "S/W OCS;",
8: "Dwell operating;"
}
status_high = {
0: "Normal state",
4: "Warning occurred",
8: "Fault occurred"
}
values = {
0: 8,
1: 4,
2: 2,
3: 1
}
stats_low = status_array[12:]
stats_mid = status_array[8:12]
stats_high = status_array[:4]
low = 0
mid = 0
high = 0
for x in range(4):
if stats_low[x] == 1:
low = low + values[x]
if stats_mid[x] == 1:
mid = mid + values[x]
if stats_high[x] == 1:
high = high + values[x]
return status_low[low] + " " + status_mid[mid] + ' ' + status_high[high]
def fault_code_a(n):
fault_code_array = int_to_bits(n,16)
""" fault = {
0: "OCT",
1: "OVT",
2: "EXT-A",
3: "EST",
4: "COL",
5: "GFT",
6: "OHT",
7: "ETH",
8: "OLT",
9: "Reserved",
10: "EXT-B",
11: "EEP",
12: "FAN",
13: "POT",
14: "IOLT",
15: "LVT"
} """
fault = {
0: "Overload Trip",
1: "Underload Trip",
2: "Inverter Overload Trip",
3: "E-Thermal Trip",
4: "Ground Fault Trip",
5: "Output Image Trip",
6: "Inmput Imaging Trip",
7: "Reserved",
8: "Reserved",
9: "NTC Trip",
10: "Overcurrent Trip",
11: "Overvoltage Trip",
12: "External Trip",
13: "Arm Short",
14: "Over Heat Trip",
15: "Fuse Open Trip"
}
faults = []
counter = 15
for x in range(16):
if fault_code_array[x] == 1:
faults = [fault[counter]] + faults
counter = counter - 1
return ' '.join(faults)
def fault_code_b(n):
fault_code_array = int_to_bits(n,8)
""" fault = {
0: "COM",
1: "Reserved",
2: "NTC",
3: "REEP",
4: "OC2",
5: "NBR",
6: "SAFA",
7: "SAFB"
} """
fault = {
0: "Reserved",
1: "Reserved",
2: "Reserved",
3: "FAN Trip",
4: "Reserved",
5: "Reserved",
6: "Pre PID Fail",
7: "Bad contact at basic I/O board",
8: "External Brake Trip",
9: "No Motor Trip",
10: "Bad Option Card",
11: "Reserved",
12: "Reserved",
13: "Reserved",
14: "Pre Over Heat Trip",
15: "Reserved"
}
faults = []
counter = 7
for x in range(8):
if fault_code_array[x] == 1:
faults = [fault[counter]] + faults
counter = counter - 1
return ' '.join(faults)
registers = [
('volume_flow', 3873, 'FLOAT', 10, 3600,2, fmaddress, None ),
('totalizer_1', 2609, 'FLOAT', 100, 3600,2, fmaddress, None ),
('totalizer_2', 2809, 'FLOAT', 100, 3600,2, fmaddress, None ),
('totalizer_3', 3009, 'FLOAT', 100, 3600,2, fmaddress, None ),
('volume_flow_units', 2102, 'INTEGER', 1,86400,1, fmaddress, volume_units),
('totalizer_1_units', 4603, 'INTEGER', 1,86400,1, fmaddress, totalizer_units),
('totalizer_2_units', 4604, 'INTEGER', 1,86400,1, fmaddress, totalizer_units),
('totalizer_3_units', 4605, 'INTEGER', 1,86400,1, fmaddress, totalizer_units),
('byte_order', 4914, 'INTEGER', 100, 3600,2, fmaddress, None),
('device_name', 7237, 'STRING', 100, 3600,5, fmaddress, None),
('serial_number', 7002, 'STRING', 100, 3600,6, fmaddress, None),
('run_status', 772, 'INTEGER', 0, 3600, 1, daddress, status_codes),
('frequency', 784, 'INTEGER', 2, 3600, 2, daddress, None),
('current', 783, 'INTEGER', 2, 3600, 2, daddress, None),
('fault_a', 815, 'INTEGER', 1, 3600, 1, daddress, fault_code_a),
('fault_b', 816, 'INTEGER', 1, 3600, 1, daddress, fault_code_b),
('pid_ref', 791, 'INTEGER', 5, 3600, 1, daddress, None),
('pid_feedback', 792, 'INTEGER', 5, 3600, 1, daddress, None),
('motor_rated_current', 4896, 'INTEGER', 300, 86400, 1, daddress, None),
('sleep_delay', 4924, 'INTEGER', 5, 86400, 1, daddress, None)
]
for register in registers:
instrument = minimalmodbus.Instrument('/dev/ttyS0', register[6]) #device, modbus slave address
instrument.debug = False
instrument.handle_local_echo = True
if register[2] == "FLOAT":
try:
value = instrument.read_float(registeraddress=register[1], functioncode=4) #register -1 for float
if register[7] != None:
value = register[7](value)
print("{} from {}: {}".format(register[0],register[6],value))
except Exception as e:
print("Error: {}".format(e))
#time.sleep(1)
elif register[2] == "INTEGER":
try:
value = instrument.read_register(registeraddress=register[1],functioncode=4) #register -1 for float
if register[7] != None:
value = register[7](value)
print("{} from {}: {}".format(register[0],register[6],value))
except Exception as e:
print("Error: {}".format(e))
#time.sleep(1)
elif register[2] == "STRING":
try:
value = instrument.read_string(register[1], register[5], functioncode=4)
value = ''.join([i if 0 < ord(i) < 128 else '' for i in value])
if register[7] != None:
value = register[7](value)
print("{} from {}: {}".format(register[0],register[6],value))
except Exception as e:
print("Error: {}".format(e))
#time.sleep(1)

View File

@@ -0,0 +1,45 @@
import client as paho
import json
from uuid import getnode as get_mac
def get_mac_address():
try:
provision = {}
deviceMap = {}
with open("/root/python_firmware/provision.json", "r") as f:
provision = json.load(f)
with open("/root/python_firmware/drivers/deviceMap.json", "r") as f:
deviceMap = json.load(f)
if provision and deviceMap:
deviceName = provision.get("deviceName")
if deviceName:
mac = deviceMap.keys()[deviceMap.values().index(deviceName)]
if mac:
return mac
except Exception as e:
print("Didn't find mac in deviceMap: {}".format(e))
try:
mac = get_mac()
mac = ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2))
return str(mac).lower()
except:
mac = "12:34:56:78:91:23"
return mac
mac = get_mac_address()
topic_base = "meshify/db/194/_/piflow/" + mac + ":01:99/"
topic_meshify = "meshify/db/194/_/mainHP/" + mac + ":00:00/connected"
c = paho.Client(client_id=mac, clean_session=True)
c.username_pw_set("admin", "columbus")
c.will_set(topic_meshify, json.dumps([{"value": False}]), 2)
c.connect("mq194.imistaway.net", 1883, keepalive=900)
c.loop_start()
def send(payload):
c.publish(topic_meshify, json.dumps([{"value": True}]), 1)
for key,value in payload["values"].items():
topic = topic_base + key
print(topic)
print(value)
c.publish(topic, json.dumps([{"value": value}]), 1)

View File

@@ -1,12 +1,14 @@
{
"files": {
"file3": "channel.py",
"file3": "Channel.py",
"file2": "utilities.py",
"file1": "transferlite.py",
"file4": "file_logger.py"
"file4": "file_logger.py",
"file5": "sendToMA.py",
"file6": "persistence.py"
},
"deviceName": "transferlite",
"driverId": "0230",
"releaseVersion": "5",
"releaseVersion": "7",
"driverFileName": "transferlite.py"
}

View File

@@ -0,0 +1,45 @@
import client as paho
import json
from uuid import getnode as get_mac
def get_mac_address():
try:
provision = {}
deviceMap = {}
with open("/root/python_firmware/provision.json", "r") as f:
provision = json.load(f)
with open("/root/python_firmware/drivers/deviceMap.json", "r") as f:
deviceMap = json.load(f)
if provision and deviceMap:
deviceName = provision.get("deviceName")
if deviceName:
mac = deviceMap.keys()[deviceMap.values().index(deviceName)]
if mac:
return mac
except Exception as e:
print("Didn't find mac in deviceMap: {}".format(e))
try:
mac = get_mac()
mac = ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2))
return str(mac).lower()
except:
mac = "12:34:56:78:91:23"
return mac
mac = get_mac_address()
topic_base = "meshify/db/194/_/transferlite/" + mac + ":01:99/"
topic_meshify = "meshify/db/194/_/mainHP/" + mac + ":00:00/connected"
c = paho.Client(client_id=mac, clean_session=True)
c.username_pw_set("admin", "columbus")
c.will_set(topic_meshify, json.dumps([{"value": False}]), 2)
c.connect("mq194.imistaway.net", 1883, keepalive=900)
c.loop_start()
def send(payload):
c.publish(topic_meshify, json.dumps([{"value": True}]), 1)
for key,value in payload["values"].items():
topic = topic_base + key
print(topic)
print(value)
c.publish(topic, json.dumps([{"value": value}]), 1)

View File

@@ -10,7 +10,7 @@ from device_base import deviceBase
from channel import PLCChannel, read_tag, write_tag,TAG_DATAERROR_SLEEPTIME
from utilities import get_public_ip_address
from file_logger import filelogger as log
from sendToMA import send
_ = None
log.info("transferlite startup")
@@ -45,6 +45,7 @@ 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
REPORT_PERIOD = 600
PLC_IP_ADDRESS = "192.168.1.10"
CHANNELS = [
PLCChannel(PLC_IP_ADDRESS, "ft01_flowmeter_bpd", "FT01_Flowmeter_BPD", "REAL", 100.0, 600),
@@ -81,7 +82,7 @@ class start(threading.Thread, deviceBase):
mqtt=mqtt, Nodes=Nodes)
self.daemon = True
self.version = "5"
self.version = "7"
self.finished = threading.Event()
self.force_send = False
self.public_ip_address = ""
@@ -116,17 +117,18 @@ class start(threading.Thread, deviceBase):
now = time.time()
if self.force_send:
log.warning("FORCE SEND: TRUE")
if int(time.time()) % 600 == 0 or self.force_send:
if int(time.time()) % REPORT_PERIOD == 0 or self.force_send:
if self.force_send:
payload = {"ts": time.time()*1000, "values": {}}
else:
payload = {"ts": round(time.time()/600)*600*1000, "values": {}}
payload = {"ts": round(time.time()/REPORT_PERIOD)*REPORT_PERIOD*1000, "values": {}}
for chan in CHANNELS:
val = chan.read()
payload["values"][chan.mesh_name] = val
payload["values"]["public_ip_address"] = self.public_ip_address
self.sendToTB(json.dumps(payload))
self.sendToTBAttributes(json.dumps({"latestReportTime": round(time.time()/600)*600*1000}))
send(payload)
self.sendToTBAttributes(json.dumps({"latestReportTime": round(time.time()/REPORT_PERIOD)*REPORT_PERIOD*1000}))
# print("transferlite driver still alive...")
if self.force_send: