def on_connect(mosq, userdata, rc): if rc != 0: log.error("Can't connect to MQTT. rc=={0}".format(rc)) sys.exit(1) for t in base_topics: mqttc.subscribe("%s/+" % t, 0) mqttc.subscribe("%s/+/obd2/#" % t, 0) mqttc.subscribe("%s/+/fms/#" % t, 0) mqttc.subscribe("%s/+/waypoints" % t, 0) if cf.g('features', 'plmn', False) == True: mqttc.subscribe("%s/+/operators" % t, 0) mqttc.subscribe("%s/+/operators/+" % t, 0) mqttc.subscribe("%s/+/cmd/#" % t, 0) mqttc.subscribe("%s/+/alarm" % t, 0) mqttc.subscribe("%s/+/start" % t, 0) mqttc.subscribe("%s/+/status" % t, 0) mqttc.subscribe("%s/+/info" % t, 0) mqttc.subscribe("%s/+/voltage/+" % t, 0) mqttc.subscribe("%s/+/gpio/+" % t, 0) if cf.g('features', 'activo', False) == True: mqttc.subscribe("%s/+/proxy/jobs/#" % t, 0) if cf.o2smonitor: mqttc.subscribe(cf.o2smonitor + "/+", 2) log.info("Connected to and subscribed to MQTT broker")
def page_tracks(): isdemo = isdemo=cf.g('pista', 'is_demo') if isdemo == True: isdemo = 1 else: isdemo = 0 return template('tracks', pistapages=cf.g('pista', 'pages'), have_xls=HAVE_XLS, isdemo=isdemo)
def page_tracks(): isdemo = isdemo = cf.g('pista', 'is_demo') if isdemo == True: isdemo = 1 else: isdemo = 0 return template('tracks', pistapages=cf.g('pista', 'pages'), have_xls=HAVE_XLS, isdemo=isdemo)
def on_operator(mosq, userdata, msg): if (skip_retained and msg.retain == 1) or len(msg.payload) == 0: return if cf.g('features', 'plmn', False) == False: return topic = msg.topic payload = str(msg.payload) watcher(mosq, topic, payload) if storage: try: o = payload.split() odata = { 'topic': topic.replace("/operators", ""), 'tst': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(int(time.time()))), 'plmn': o[0], 'extended': " ".join(o[1:]), } op = Operators(**odata) op.save() except Exception, e: log.error("Can't store operators in DB: {0}".format(str(e)))
def config_js(): ''' Produce a `config.js' from the [websocket] section of our config file. We have to muck about a bit to convert None etc. to JavaScript types ... ''' newconf = cf.config('websocket') basic_auth = True if 'basic_auth' in newconf and newconf['basic_auth'] == False: basic_auth = False newconf['activo'] = cf.g('features', 'activo', False) for key in newconf: if type(newconf[key]) == str: if newconf[key][0] != '"' and newconf[key][0] != '"': newconf[key] = "'" + newconf[key] + "'" if type(newconf[key]) == bool: newconf[key] = 'true' if newconf[key] else 'false' # print key, " = ", type(newconf[key]), " : ", newconf[key] newconf['configfile'] = cf.configfile if basic_auth == True: u = request.auth[0] u = u.replace("'", "\\'") p = request.auth[1] p = p.replace("'", "\\'") newconf['username'] = "******".format(u) newconf['password'] = "******".format(p) response.content_type = 'text/javascript; charset: UTF-8' return template('config-js', newconf)
def config_js(): ''' Produce a `config.js' from the [websocket] section of our config file. We have to muck about a bit to convert None etc. to JavaScript types ... ''' newconf = cf.config('websocket') basic_auth = True if 'basic_auth' in newconf and newconf['basic_auth'] == False: basic_auth = False newconf['activo'] = cf.g('features', 'activo', False) for key in newconf: if type(newconf[key]) == str: if newconf[key][0] != '"' and newconf[key][0] != '"': newconf[key] = "'" + newconf[key] + "'" if type(newconf[key]) == bool: newconf[key] = 'true' if newconf[key] else 'false'; # print key, " = ", type(newconf[key]), " : ", newconf[key] newconf['configfile'] = cf.configfile if basic_auth == True: u = request.auth[0] u = u.replace("'", "\\'") p = request.auth[1] p = p.replace("'", "\\'") newconf['username'] = "******".format(u) newconf['password'] = "******".format(p) response.content_type = 'text/javascript; charset: UTF-8' return template('config-js', newconf)
def on_operator(mosq, userdata, msg): if (skip_retained and msg.retain == 1) or len(msg.payload) == 0: return if cf.g('features', 'plmn', False) == False: return topic = msg.topic payload = str(msg.payload) watcher(mosq, topic, payload) if storage: try: o = payload.split() odata = { 'topic' : topic.replace("/operators", ""), 'tst' : time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(int(time.time()))), 'plmn' : o[0], 'extended' : " ".join(o[1:]), } op = Operators(**odata) op.save() except Exception, e: log.error("Can't store operators in DB: {0}".format(str(e)))
def watcher(mosq, topic, data): watcher_topic = cf.g('features', 'watcher', None) if watcher_topic is None: return try: prefix, suffix = tsplit(topic) wt = watcher_topic.format(prefix) + "/" + suffix except Exception, e: log.error("Cannot format watcher_topic: {0}".format(str(e))) return
def on_job(mosq, userdata, msg): # ignore if 'activo' hasn't been enabled if cf.g('features', 'activo', False) == False: return # topic owntracks/gw/B2/proxy/jobs/[active|<jobid>] base_topic, suffix = tsplit(msg.topic) parts = suffix.split('/') # topic owntracks/user/device/proxy/jobs/[currentjob|active|<jobid> if len(parts) == 3: last_part = parts[len(parts) - 1] # suffix proxy/jobs/[currentjob|job<jobid>] if last_part == 'active': # handle this active job change event on_activejob(mosq, msg, base_topic) elif last_part == 'currentjob': # skip current jobs w/o timestamp pass else: # update the job name list jobnames[int(last_part)] = msg.payload # topic owntracks/user/device/proxy/jobs/[job|place|machine]/<jobid> # topic owntracks/user/device/proxy/jobs/currentjob/<timestamp> elif len(parts) == 4: id_part = parts[len(parts) - 2] if id_part == 'currentjob': timestamp = long(parts[len(parts) - 1]) on_currentjob(mosq, msg, base_topic, timestamp) elif id_part == 'job': job = int(parts[len(parts) - 1]) jobnames[job] = msg.payload elif id_part == 'place': place = int(parts[len(parts) - 1]) placeparts = msg.payload.split(' ') placenames[place] = placeparts[0] elif id_part == 'machine': machine = int(parts[len(parts) - 1]) machineparts = msg.payload.split(' ') machinenames[machine] = machineparts[0] # topic owntracks/user/device/proxy/jobs/job/<jobid>/<taskid> elif len(parts) == 5: id_part = parts[len(parts) - 3] if id_part == 'job': job = int(parts[len(parts) - 2]) task = int(parts[len(parts) - 1]) tasknames[job*10000 + task] = msg.payload
def on_job(mosq, userdata, msg): # ignore if 'activo' hasn't been enabled if cf.g('features', 'activo', False) == False: return # topic owntracks/gw/B2/proxy/jobs/[active|<jobid>] base_topic, suffix = tsplit(msg.topic) parts = suffix.split('/') # topic owntracks/user/device/proxy/jobs/[currentjob|active|<jobid> if len(parts) == 3: last_part = parts[len(parts) - 1] # suffix proxy/jobs/[currentjob|job<jobid>] if last_part == 'active': # handle this active job change event on_activejob(mosq, msg, base_topic) elif last_part == 'currentjob': # skip current jobs w/o timestamp pass else: # update the job name list jobnames[int(last_part)] = msg.payload # topic owntracks/user/device/proxy/jobs/[job|place|machine]/<jobid> # topic owntracks/user/device/proxy/jobs/currentjob/<timestamp> elif len(parts) == 4: id_part = parts[len(parts) - 2] if id_part == 'currentjob': timestamp = long(parts[len(parts) - 1]) on_currentjob(mosq, msg, base_topic, timestamp) elif id_part == 'job': job = int(parts[len(parts) - 1]) jobnames[job] = msg.payload elif id_part == 'place': place = int(parts[len(parts) - 1]) placeparts = msg.payload.split(' ') placenames[place] = placeparts[0] elif id_part == 'machine': machine = int(parts[len(parts) - 1]) machineparts = msg.payload.split(' ') machinenames[machine] = machineparts[0] # topic owntracks/user/device/proxy/jobs/job/<jobid>/<taskid> elif len(parts) == 5: id_part = parts[len(parts) - 3] if id_part == 'job': job = int(parts[len(parts) - 2]) task = int(parts[len(parts) - 1]) tasknames[job * 10000 + task] = msg.payload
def save_rawdata(topic, payload): if not storage or cf.g('features', 'rawdata', False) == False: return try: rawdata = { 'topic' : topic, 'tst' : time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(int(time.time()))), 'payload' : payload, } rd = RAWdata(**rawdata) rd.save() except Exception, e: log.error("Cannot store rawdata for topic {0}: {1}".format(topic, str(e)))
def save_rawdata(topic, payload): if not storage or cf.g('features', 'rawdata', False) == False: return try: rawdata = { 'topic': topic, 'tst': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(int(time.time()))), 'payload': payload, } rd = RAWdata(**rawdata) rd.save() except Exception, e: log.error("Cannot store rawdata for topic {0}: {1}".format( topic, str(e)))
def page_hw(): current_user = request.auth[0] usertids = getusertids(current_user) device_list = [] # Find all devices in Inventory and extract their info into a list # of objects. Ensure values of hash keys are None if unset or # the template will bail out. try: query = (Inventory .select(Inventory) .where( (Inventory.tid << usertids) ) ) query = query.order_by(Inventory.tid.asc()) for q in query.naive(): try: device_list.append({ 'tid' : q.tid, 'imei' : q.imei, 'version' : q.version, 'tstamp' : q.startup, 'topic' : q.topic, }) except: pass except: pass # device_list will be empty => no data, which is OK here device_list.sort(key=lambda x: x['tid'], reverse=False) params = { 'devices' : device_list, 'pistapages' : cf.g('pista', 'pages'), } return template('hw', params)
def createalltables(): silent = True db.connect() Location.create_table(fail_silently=silent) Lastloc.create_table(fail_silently=silent) Waypoint.create_table(fail_silently=silent) Geo.create_table(fail_silently=silent) User.create_table(fail_silently=silent) Acl.create_table(fail_silently=silent) Inventory.create_table(fail_silently=silent) Params.create_table(fail_silently=silent) Obd2.create_table(fail_silently=silent) Fms.create_table(fail_silently=silent) if cf.g('features', 'plmn', False) == True: try: Operators.create_table(fail_silently=silent) except Exception, e: print str(e)
def page_hw(): current_user = request.auth[0] usertids = getusertids(current_user) device_list = [] # Find all devices in Inventory and extract their info into a list # of objects. Ensure values of hash keys are None if unset or # the template will bail out. try: query = (Inventory.select(Inventory).where( (Inventory.tid << usertids))) query = query.order_by(Inventory.tid.asc()) for q in query.naive(): try: device_list.append({ 'tid': q.tid, 'imei': q.imei, 'version': q.version, 'tstamp': q.startup, 'topic': q.topic, }) except: pass except: pass # device_list will be empty => no data, which is OK here device_list.sort(key=lambda x: x['tid'], reverse=False) params = { 'devices': device_list, 'pistapages': cf.g('pista', 'pages'), } return template('hw', params)
def page_jobedit(): return template('jobedit', pistapages=cf.g('pista', 'pages'))
def page_map(): return template('map', pistapages=cf.g('pista', 'pages'))
def page_console(): return template('status', pistapages=cf.g('pista', 'pages'))
from owntracks.util import tsplit import dateutil.parser import tempfile import codecs sys.stdout = codecs.getwriter("utf-8")(sys.__stdout__) log = logging.getLogger(__name__) SEEN_DRIVING = 1200 MAX_VOLTAGES = 10 LASTLOC_EXPIRY = 3600 MAX_JOBS = 16 INACTIVE_JOB = 0 storage = cf.g('features', 'storage', 'True') maptopic = None jobtopic = None devices = {} imeilist = {} jobs = {} jobnames = {} tasknames = {} placenames = {} machinenames = {} createalltables() jobnames[0] = "" tasknames[0] = "" placenames[0] = "" machinenames[0] = ""
def page_table(): activo = cf.g('features', 'activo', False) return template('table', pistapages=cf.g('pista', 'pages'), activo=activo)
import sys import os import owntracks import logging import bottle from bottle import response, template, static_file, request import json import time from owntracks import cf from owntracks.dbschema import db, User, Acl, Params, fn, Location, createalltables import paho.mqtt.client as paho from owntracks.auth import PistaAuth log = logging.getLogger(__name__) cacert_file = cf.g('ctrld', 'cacert_file') if not os.path.isfile(cacert_file) or not os.access(cacert_file, os.R_OK): log.error("Cannot open cacert_file ({0})".format(cacert_file)) sys.exit(2) createalltables() auth = PistaAuth() app = application = bottle.Bottle() def notauth(reason): return bottle.HTTPResponse(status=403, body=json.dumps({"message": reason}))
def page_job(): return template('jobs', pistapages=cf.g('pista', 'pages'), have_xls=HAVE_XLS, isdemo=0)
def page_about(): return template('about', pistapages=cf.g('pista', 'pages'))
Waypoint.create_table(fail_silently=silent) Geo.create_table(fail_silently=silent) User.create_table(fail_silently=silent) Acl.create_table(fail_silently=silent) Inventory.create_table(fail_silently=silent) Params.create_table(fail_silently=silent) Obd2.create_table(fail_silently=silent) Fms.create_table(fail_silently=silent) if cf.g('features', 'plmn', False) == True: try: Operators.create_table(fail_silently=silent) except Exception, e: print str(e) if cf.g('features', 'rawdata', False) == True: try: RAWdata.create_table(fail_silently=silent) except Exception, e: print str(e) if cf.g('features', 'activo', False) == True: try: Job.create_table(fail_silently=silent) except Exception, e: print str(e) def dbconn(): # Attempt to connect if not already connected. For MySQL, take care of MySQL 2006 try: db.connect()
def on_message(mosq, userdata, msg): if (skip_retained and msg.retain == 1): return topic = msg.topic if len(msg.payload) == 0: ''' Clear out everthing we know of this vehicle? We cannot delete our own MQTT topics, because that'll result in a loop. ''' # FIXME: we should subscribe to topic/# to find 'em all... # for s in ['status', 'start', 'gpio', 'voltage', 'operators', 'info']: # mosq.publish("%s/%s" % (topic, s), None, qos=2, retain=True) # mosq.publish(topic, None, qos=2, retain=True) # mosq.publish(maptopic + "/" + topic, None, qos=2, retain=True) return types = ['location', 'waypoint'] payload = str(msg.payload) save_rawdata(topic, msg.payload) if len(msg.payload) < 1: return item = payload2location(topic, payload) if item is None or type(item) != dict: return if '_type' not in item or item['_type'] not in types: return if 'lat' not in item or 'lon' not in item: return tid = item.get('tid') tst = item.get('tst', int(time.time())) lat = item.get('lat') lon = item.get('lon') trip = item.get('trip', 0) dist = item.get('dist', 0) vel = item.get('vel', 0) t_ignore = cf.g('features', 't_store', [ 'p' ]) if item['t'] in t_ignore: return item['topic'] = topic orig_tst = tst tstamp = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(tst)) item['tst'] = tstamp if storage: try: dbconn() except Exception, e: log.error("Reconnect to DB: {0}".format(str(e))) return
def index(): return template('index', pistapages=cf.g('pista', 'pages'), isdemo=cf.g('pista', 'is_demo'))
def on_message(mosq, userdata, msg): if (skip_retained and msg.retain == 1): return topic = msg.topic if len(msg.payload) == 0: ''' Clear out everthing we know of this vehicle? We cannot delete our own MQTT topics, because that'll result in a loop. ''' # FIXME: we should subscribe to topic/# to find 'em all... # for s in ['status', 'start', 'gpio', 'voltage', 'operators', 'info']: # mosq.publish("%s/%s" % (topic, s), None, qos=2, retain=True) # mosq.publish(topic, None, qos=2, retain=True) # mosq.publish(maptopic + "/" + topic, None, qos=2, retain=True) return types = ['location', 'waypoint'] payload = str(msg.payload) save_rawdata(topic, msg.payload) if len(msg.payload) < 1: return item = payload2location(topic, payload) if item is None or type(item) != dict: return if '_type' not in item or item['_type'] not in types: return if 'lat' not in item or 'lon' not in item: return tid = item.get('tid') tst = item.get('tst', int(time.time())) lat = item.get('lat') lon = item.get('lon') trip = item.get('trip', 0) dist = item.get('dist', 0) vel = item.get('vel', 0) t_ignore = cf.g('features', 't_store', ['p']) if item['t'] in t_ignore: return item['topic'] = topic orig_tst = tst tstamp = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(tst)) item['tst'] = tstamp if storage: try: dbconn() except Exception, e: log.error("Reconnect to DB: {0}".format(str(e))) return
Waypoint.create_table(fail_silently=silent) Geo.create_table(fail_silently=silent) User.create_table(fail_silently=silent) Acl.create_table(fail_silently=silent) Inventory.create_table(fail_silently=silent) Params.create_table(fail_silently=silent) Obd2.create_table(fail_silently=silent) Fms.create_table(fail_silently=silent) if cf.g('features', 'plmn', False) == True: try: Operators.create_table(fail_silently=silent) except Exception, e: print str(e) if cf.g('features', 'rawdata', False) == True: try: RAWdata.create_table(fail_silently=silent) except Exception, e: print str(e) if cf.g('features', 'activo', False) == True: try: Job.create_table(fail_silently=silent) except Exception, e: print str(e) def dbconn(): # Attempt to connect if not already connected. For MySQL, take care of MySQL 2006 try:
import sys import os import owntracks import logging import bottle from bottle import response, template, static_file, request import json import time from owntracks import cf from owntracks.dbschema import db, User, Acl, Params, fn, Location, createalltables import paho.mqtt.client as paho from owntracks.auth import PistaAuth log = logging.getLogger(__name__) cacert_file = cf.g('ctrld', 'cacert_file') if not os.path.isfile(cacert_file) or not os.access(cacert_file, os.R_OK): log.error("Cannot open cacert_file ({0})".format(cacert_file)) sys.exit(2) createalltables() auth = PistaAuth() app = application = bottle.Bottle() def notauth(reason): return bottle.HTTPResponse(status=403, body=json.dumps({"message": reason})) @app.route('/') def show_index():