#!/usr/bin/python import types import traceback import binascii import threading import time import thread import os import struct import sys import serial import minimalmodbus import pickle from device_base import deviceBase from datetime import datetime import requests try: import json except: import simplejson as json import calendar from math import ceil, floor data_channels = { "IntakeTemperature":{"modbus_register":0, "value":"", "last_value":"", "last_send_time":0, "min_change_limit":0, "change_threshold":0, "min_upload_time":180}, "IntakePressure": {"modbus_register":1, "value":"", "last_value":"", "last_send_time":0, "min_change_limit":0, "change_threshold":0, "min_upload_time":180}, "WindingTemperature": {"modbus_register":2, "value":"", "last_value":"", "last_send_time":0, "min_change_limit":0, "change_threshold":0, "min_upload_time":180}, "DischargeTemperature": {"modbus_register":5, "value":"", "last_value":"", "last_send_time":0, "min_change_limit":0, "change_threshold":0, "min_upload_time":180}, "DischargePressure": {"modbus_register":6, "value":"", "last_value":"", "last_send_time":0, "min_change_limit":0, "change_threshold":0, "min_upload_time":180}, "VibrationX": {"modbus_register":3, "value":"", "last_value":"", "last_send_time":0, "min_change_limit":0, "change_threshold":0, "min_upload_time":180}, "VibrationY": {"modbus_register":4, "value":"", "last_value":"", "last_send_time":0, "min_change_limit":0, "change_threshold":0, "min_upload_time":180} } status_channels = { "DownholeStatus": {"modbus_register":97, "map":"mainStatus" "value":"", "last_value":"", "last_send_time":0, "min_change_limit":0, "change_threshold":0, "min_upload_time":180} } map = { "mainStatus": { 0: "OK", 1: "Connecting", 2: "Open circuit", 3: "Shorted", 4: "Cannot decode" }, } class start(threading.Thread, deviceBase): def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None, companyId=None, offset=None, mqtt=None, Nodes=None): 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.forceSend = True self.version = "2" self.cardLoopTimer = 600 self.finished = threading.Event() 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): channels["status"]["last_value"] = "" def run(self): self.runLoopStatus = "" while True: try: runLoopStatus = "readStatusRegisters" self.readStatusRegisters() runLoopStatus = "readDataRegisters" self.readDataRegisters() runLoopStatus = "Complete" time.sleep(3) except Exception, e: sleep_timer = 20 print "Error during {0} of run loop: {1}\nWill try again in {2} seconds...".format(runLoopStatus, e, sleep_timer) time.sleep(sleep_timer) def readStatusRegisters(self): for entry in day: if go_channels.has_key(entry): #"percent_run":{"meshifyName":"go_percent_run","last_value":"","last_send_time":0,"data_type":"float","change_amount":0}, if go_channels[entry]["last_value"] != day[entry]: print entry, day[entry] print go_channels[entry]["meshifyName"], day[entry], timestamp self.sendtodb(go_channels[entry]["meshifyName"], day[entry], timestamp) go_channels[entry]["last_value"] = day[entry] def checkBackup(self): backupList = json.loads(requests.get(self.device_address + "/json/backups").text) file = backupList["backups"][0] data = json.loads(requests.get(self.device_address + "/json/backups/" + file).text) timestamp = time.time() if data != self.wellSetup or self.forceSend: self.sendtodbJSON("well_setup", json.dumps(data), timestamp) self.wellSetup = data; with open('wellSetup.p', 'wb') as handle: pickle.dump(self.wellSetup, handle) def checkEvents(self): data = json.loads(requests.get(self.device_address + "/json/event_list").text) events = data["events"] for event in events: if int(event["id"]) not in self.eventIds: timestamp = calendar.timegm(time.strptime(event["datetime"], '%Y-%m-%dT%H:%M:%S.%fZ')) #we have a new event self.sendtodbJSON("events", json.dumps(event), timestamp) self.eventIds.append(int(event["id"])) if len(self.eventIds) > 50: del self.eventIds[0] with open('eventIds.p', 'wb') as handle: pickle.dump(self.eventIds, handle) def checkStatus(self): statusMap = { 0:'Stopped', 1:'Running', 2:'Pumped Off', 3:'Faulted', 4:'Starting', 5:'Recovering', 100:'Read Error', 1000:'PLC Error', 9999:'No Response' } st_response = requests.get(self.device_address + "/json/status") if st_response.status_code == 200: data = json.loads(st_response.text) date = data["ISOdate"] status = statusMap[int(data["status"])] if channels["status"]["last_value"] != status: self.statusChanged = True print "Status has changed from {0} to {1} @ {2}".format(channels["status"]["last_value"], status, time.time()) else: self.statusChanged = False if self.statusChanged or self.forceSend: self.status = status timestamp = int(time.mktime(time.strptime(date, '%Y-%m-%dT%H:%M:%S.%fZ'))) self.sendtodb("status", status, timestamp) channels["status"]["last_value"] = status self.checkLatestCard() def checkDailyTotals(self): data = json.loads(requests.get(self.device_address + "/json/totals").text) total = data["totals"] if total['status'] == "success": timestamp = 0 for val in total['values']: if dt_channels.has_key(val['name']): if ((time.time() - int(dt_channels[val['name']]['last_time_uploaded'])) > int(dt_channels[val['name']]['min_time_between_uploads'])): if (float(val['value']) >= (float(dt_channels[val['name']]["last_value"]) + float(dt_channels[val['name']]["change_amount"]))) or (float(val['value']) <= (float(dt_channels[val['name']]["last_value"]) - float(dt_channels[val['name']]["change_amount"]))): print("[dailyTotal] {0}: {1}".format(val['name'], val['value'])) self.sendtodb(dt_channels[val['name']]["meshify_channel"], float(val['value']), timestamp) dt_channels[val['name']]["last_value"] = float(val['value']) dt_channels[val['name']]["last_time_uploaded"] = time.time() else: print("checkDailyTotalsError: {0}".format(total.message)) def checkGaugeOffData(self): data = json.loads(requests.get(self.device_address + "/json/history").text) day = data["hist"] # print day["gauge_date"] #timestamp = calendar.timegm(time.strptime(day["gauge_date"], '%Y-%m-%dT%H:%M:%S.%fZ')) timestamp = time.mktime(time.strptime(day["gauge_date"], '%Y-%m-%dT%H:%M:%S.%Z')) for entry in day: if go_channels.has_key(entry): #"percent_run":{"meshifyName":"go_percent_run","last_value":"","last_send_time":0,"data_type":"float","change_amount":0}, if go_channels[entry]["last_value"] != day[entry]: print entry, day[entry] print go_channels[entry]["meshifyName"], day[entry], timestamp self.sendtodb(go_channels[entry]["meshifyName"], day[entry], timestamp) go_channels[entry]["last_value"] = day[entry] def checkLatestCard(self): latest = requests.get(self.device_address + "/json/latest") latest = json.loads(latest.text) folder = str(latest["folder"]) file = latest["file"].replace(".csv", "") #check the card to see if its new # 1. if its new send the folder/file_name to the card_history channel # 2. if its new and its been 10 minutes since you last sent an entire card, then send up all of the data if channels["card_history"]["last_value"] != (folder + "/" + file): #we have a new card #get the data for this event data = json.loads(requests.get(self.device_address + "/json/" + folder + "/" + file).text) dateTime = str(data["contents"]["utctime"]) #timestamp = time.mktime(time.strptime(dateTime, '%Y-%m-%d %H:%M:%S.%f')) #timestamp = calendar.timegm(time.strptime(dateTime, '%Y-%m-%d %H:%M:%S.%f')) timestamp = time.mktime(time.strptime(dateTime, '%Y-%m-%d %H:%M:%S.%f')) print "New card detected @ {0}".format(datetime.strftime(datetime.fromtimestamp(timestamp),"%Y-%m-%d %H:%M:%S.%f")) #set the last value = to current value and upload your data channels["card_history"]["last_value"] = (folder + "/" + file) self.sendtodb("card_history", (folder + "/" + file), timestamp) #check the last time the card was updated if (time.time() - int(channels["card_history"]["last_time_uploaded"])) > self.cardLoopTimer or self.statusChanged or self.forceSend: #its been 10 minutes, send the full upload print "Either status has changed or last stored card is too old." channels["card_history"]["last_time_uploaded"] = time.time() self.process_card(data, timestamp, sendCards=True) return self.process_card(data, timestamp, sendCards=False) def process_card(self, data, timestamp, sendCards=False): #if sendCards = True then we upload all data no matter what, including cards #check what type of data it is #check if its changed, if it has, how long has it been since it changed #NOTE: the initial vaue of "" is given to all channels in the channels object, # so to avoid comparing a string to a float, and to make sure on startup we send all of the values, the first time through we send everything that has a "" as its last value # We don't want to store any data on starting, just the cards if self.status != 'Starting': for channel in data["contents"]: if channels.has_key(channel): if channels[channel]["data_type"] == "str": if (data["contents"][channel] != channels[channel]["last_value"] and ((time.time() - int(channels[channel]["last_time_uploaded"])) > int(channels[channel]["min_time_between_uploads"]))) or sendCards == True: print "new value for: ", channel print data["contents"][channel] self.sendtodb(channel, str(data["contents"][channel]), int(timestamp)) channels[channel]["last_value"] = data["contents"][channel] channels[channel]["last_time_uploaded"] = time.time() if channels[channel]["data_type"] == "float" or channels[channel]["data_type"] == "int": if channels[channel]["last_value"] == "": #print "first time getting data" print "new value for: ", channel print data["contents"][channel] self.sendtodb(channel, str(data["contents"][channel]), int(timestamp)) channels[channel]["last_value"] = data["contents"][channel] channels[channel]["last_time_uploaded"] = time.time() if (abs(float(data["contents"][channel]) - float(channels[channel]["last_value"])) > channels[channel]["change_amount"] and ((time.time() - int(channels[channel]["last_time_uploaded"])) > int(channels[channel]["min_time_between_uploads"]))) or sendCards == True: # print "first time getting data" print "new value for: ", channel print data["contents"][channel] self.sendtodb(channel, str(data["contents"][channel]), int(timestamp)) channels[channel]["last_value"] = data["contents"][channel] channels[channel]["last_time_uploaded"] = time.time() if sendCards: sc = data["s"] dc = data["d"] for i in range(len(data["d"])): try: for x in range(len(data["d"][i])): data["d"][i][x] = float('%.3f' % data["d"][i][x]) except Exception, e: print e for i in range(len(data["s"])): try: for x in range(len(data["s"][i])): data["s"][i][x] = float('%.3f' % data["s"][i][x]) except Exception, e: print e sc = data["s"] dc = data["d"] newSc = "[" for i in sc: try: if i[0] is None: continue if i[0] != 0.0 and i[1]!= 0.0: newSc += "[" + str(i[0]) + "," + str(i[1]) + "]," except: pass newSc += "[" + str(sc[0][0]) + "," + str(sc[0][1]) + "]" newSc += "]" newDc = "[" for i in dc: try: if i[0] is None: continue if i[0] != 0.0 and i[1]!= 0.0: newDc += "[" + str(i[0]) + "," + str(i[1]) + "]," except: pass newDc += "[" + str(dc[0][0]) + "," + str(dc[0][1]) + "]" newDc += "]" self.sendtodb("sc", newSc, timestamp) self.sendtodb("dc", newDc, timestamp) def getLatestXCards(self, numCards): data = json.loads(requests.get(self.device_address + "/json/latest/"+ str(int(numCards))).text) for card in data['cards']: card_data = json.loads(requests.get(self.device_address + "/json/" + data['folder'] + "/" + card).text) dateTime = str(card_data["contents"]["utctime"]) timestamp = time.mktime(time.strptime(dateTime, '%Y-%m-%d %H:%M:%S.%f')) self.process_card(card_data, timestamp, sendCards=True) def poc_get_card(self, name, value): self.getcard(value) def poc_sync(self, name, value): self.sendtodb("connected", "true", 0) return True def poc_set_address(self, name, value): self.device_address = value return True def poc_refresh_data(self, name, value): self.forceSend = True return True def poc_read_tag(self, name, value): print "Reading Tag {0}".format(str(value)) tagObj = readTag.readTag(str(value)) print "tagObj: {0}".format(tagObj) if tagObj['status'] == 'success': result = "{{'tag':{0},'value':{1}}}".format(str(value),str(tagObj['value'])) self.sendtodb("read_tag_value", result, 0) return True else: return tagObj['message']