class Publisher(): def __init__(self, name, version, host, port, username, password): self._name = name self._version = version self._host = host self._port = port self._username = username self._password = password self.log = Log() self._CLEAN_SESSION = True def publish(self, topic, data, q, r, debug=True): try: client = mqtt.Client("global_publisher", clean_session=self._CLEAN_SESSION) client.on_connect = self.on_connect client.on_disconnect = self.on_disconnect client.on_publish = self.on_publish if (self._username != None): client.username_pw_set(username=self._username, password=self._password) client.connect(self._host, port=self._port, keepalive=60, bind_address="") topic = self._version + "/" + self._name + "/" + topic + "/response" client.loop_start() rc = client.publish(topic, payload=json.dumps(data), qos=q, retain=r) client.loop_stop() client.disconnect() if (debug): if rc[0] == 0: self.log.print( "Global publisher on topic: " + topic + " QoS:" + str(q) + " Retain:" + str(r) + " RC:" + str(rc), "OK") else: self.log.print( "Global publish unable to publish on topic: " + topic, str(r)) except Exception as e: self.log.print("Global Publisher error: ", format(e)) def on_connect(self, client, userdata, flags, rc): self.log.print( client.name + ":on_connect callback result, Flags: " + str(flags), str(rc)) def on_disconnect(self): pass def on_publish(self, client, userdata, mid): self.log.print("publish response, MID: " + mid + "...", "OK")
class Threads(threading.Thread): def __init__(self,tid,name,lock,obj): threading.Thread.__init__(self) self._id=str(tid) self._name=name self._lock=lock self._obj=obj self.log=Log() self.log.print("Creating Thread Named: "+self._name+"; ID: "+self._id,"OK") def run(self): self._obj.start()
class Database(): def __init__(self): self.log = Log() def test(self): db = pymysql.connect(CONFIG['mysql_host'], CONFIG['mysql_username'], CONFIG['mysql_password'], CONFIG['mysql_db']) cursor = db.cursor() cursor.execute("SELECT VERSION()") # Fetch a single row using fetchone() method. data = cursor.fetchone() print("Database version : %s " % data) # disconnect from server db.close() def get_user(self, token): db = pymysql.connect(CONFIG['mysql_host'], CONFIG['mysql_username'], CONFIG['mysql_password'], CONFIG['mysql_db']) cursor = db.cursor() cursor.execute( "SELECT users.id,users.phone FROM users LEFT JOIN tracker_tokens on tracker_tokens.user_id = users.id where tracker_tokens.token = '%s'" % token) data = cursor.fetchone() db.close() return data def post_track(self, id, lat, lng): try: db = pymysql.connect(CONFIG['mysql_host'], CONFIG['mysql_username'], CONFIG['mysql_password'], CONFIG['mysql_db']) cursor = db.cursor() datetime = strftime("%Y-%m-%d %H:%M:%S", localtime()) cursor.execute( "INSERT INTO `location_histories` (`id`,`user_id`,`lat`,`lng`,`timestamp`,`created_at`, `updated_at`) VALUES (NULL, %s, %s, %s, current_timestamp(),NULL,NULL);", (str(id), lat, lng)) db.commit() except Exception as e: self.log.print("Error occured in insert: ", format(e)) return 0
class App(): def __init__(self): self.database = Database() self._name=CONFIG['app_name'] self._version=CONFIG['app_version'] self._broker_host=CONFIG['broker_host'] self._broker_port=CONFIG['broker_port'] self._broker_username=CONFIG['broker_username'] self._broker_password=CONFIG['broker_password'] self._lock=threading.Lock() self.log=Log() def start(self): try: api=Api(self._name,self._version,self._broker_host,self._broker_port,self._broker_username,self._broker_password) self.log.print("Listening to all APIs","OK") sub=Subscriber(api,self._name,self._version,self._broker_host,self._broker_port,self._broker_username,self._broker_password,self._lock) sub_thread = Threads(1, "Subscriber Thread",self._lock,sub) sub_thread.start() sub_thread.join() except Exception as e: self.log.print("Exception in the main thread: ",format(e)) # self.database.get_user('71f7bb0c6db392201e3c')
class Api(): def __init__(self, name, version, host, port, username, password): self._name = name self._version = version self.publish = Publisher(name, version, host, port, username, password) self.log = Log() self.db = Database() def track(self, topic, payload): dat = {} dat1 = {} topic1 = '' try: temp = json.loads(payload) if (temp['key'] == "" or temp['data']['lat'] == "" or temp['data']['lng'] == ""): self.log.print("Bad request...", "OK") dat['status'] = 'error' dat['status_code'] = 400 dat['message'] = 'Required Parameters empty' dat['data'] = {} dat['key'] = 'NULL' else: result = self.db.get_user(temp['key']) if not result: self.log.print("Unauthorized request...", "OK") dat['status'] = 'error' dat['status_code'] = 401 dat['message'] = 'Unauthorized: invalid key given' dat['data'] = {} dat['key'] = 'NULL' else: phone = result[1] self.db.post_track(result[0], temp['data']['lat'], temp['data']['lng']) dat1['data'] = { 'lat': temp['data']['lat'], 'lng': temp['data']['lng'] } topic1 = phone dat['status'] = 'success' dat['status_code'] = 200 dat['message'] = 'Co-ordinates successfully recorded' dat['data'] = {} except Exception as e: self.log.print("Error parsing request json", format(e)) dat['status'] = 'error' dat['status_code'] = 400 dat['message'] = 'Bad Request: error parsing json' dat['data'] = {} dat['key'] = 'NULL' self.publish.publish(topic1, dat1, 0, True, False) self.publish.publish(topic, dat, 0, False, False) return 0 def qos(self): return 1
class Hotspot(): def __init__(self,interface,ssid,key_mgmt,pswd): self.log=Log() self._interface=interface self._ssid=ssid self._key_mgmt=key_mgmt self._pswd=pswd self._hostapd='/etc/hostapd/hostapd.conf' self._dnsmasq='/etc/dnsmasq.conf' def create(self): try: self.log.print("Creating Hotspot: "+self._ssid+"...","OK") return True except Exception as e: return False def destroy(self): try: self.log.print("Destorying Hotspot: "+self._ssid+"...","OK") return True except Exception as e: return False
class Mapper(): def __init__(self, name, version, api): self._api = api self._name = name self._version = version self.log = Log() def map(self, topic, payload): try: _a = self.topic_parser(topic) _f = self.route_parser(ROUTES[_a]) return getattr(self._api, _f)(_a, payload) except Exception as e: self.log.print("Mapper:Unauthorised function call", format(e)) return 0 def topic_parser(self, topic): try: c = 0 top = topic.split('/') subtopic = '' for t in top: if (t == self._version or t == self._name or t == 'request'): c = c + 1 else: subtopic = subtopic + '/' + t if (c == 3): return subtopic[1:] return None except Exception as e: self.log.print("Mapper.topic_parser() error occured: ", format(e)) return None def route_parser(self, route): try: subroute = route.split('@') return subroute[0] except Exception as e: self.log.print("Mapper.route_parser() error occured: ", format(e)) return None
class Boot(): def __init__(self): self.log=Log() self.log.create_log() self.log.print("Log file created...","OK") def start(self): self.log.print("validating wifi credentials...","OK") while True: if(self.manage_wifi()): break self.log.print("Configuration complete...","OK") self.log.print("Starting new instance of the app...","OK") app=App(CONFIG['app_name'],CONFIG['app_key'],CONFIG['app_version']) app.start() def manage_wifi(self): wifi=Wifi(CONFIG['interface'],CONFIG['wifi_ssid'],CONFIG['wifi_key_mgmt'],CONFIG['wifi_password']) status=wifi.status() if(status>=0): if(status==1): return True if(status==0): if(wifi.scan()): wifi.disconnect() wifi.connect() return False else: self.log.print("Creating a hotstop to configure the device...","OK") hotspot=Hotspot(CONFIG['interface'],CONFIG['hotspot_ssid'],CONFIG['hotspot_key_mgmt'],CONFIG['hotspot_password']) if(hotspot.create()): return True else: self.log.print("Unable to create the hotspot...","OK") return False else: if(wifi.scan()): wifi.disconnect() wifi.connect() return False else: self.log.print("Creating a hotstop to configure the device...","OK") hotspot=Hotspot(CONFIG['interface'],CONFIG['hotspot_ssid'],CONFIG['hotspot_key_mgmt'],CONFIG['hotspot_password']) if(hotspot.create()): return True else: self.log.print("Unable to create the hotspot...","OK") return False
class Wifi(): def __init__(self,interface,ssid,key_mgmt,pswd): self.log=Log() self._interface=interface self._ssid=ssid self._key_mgmt=key_mgmt self._pswd=pswd self._wpa_supplicant='/etc/wpa_supplicant/wpa_supplicant.conf' def connect(self): try: data='' self.log.print("Connecting to "+self._ssid+"...","OK") if(self._key_mgmt=='TRUE'): dat = subprocess.Popen(['wpa_passphrase',self._ssid,self._pswd], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for line in dat.stdout: line=line.decode() data=data+line #data = 'network={\nssid="'+self._ssid+'"\npsk="'+self._pswd+'"\n}\n' else: data = 'network={\nssid="'+self._ssid+'"\nkey_mgmt=NONE\n}\n' if(self.write_config(data)==False): self.log.print("Unable to connect to wifi: "+self._ssid+"...","OK") return False ps = subprocess.Popen(['wpa_supplicant','-q','-B','-i',self._interface,'-D','nl80211,wext','-c',self._wpa_supplicant], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) time.sleep(15) self.log.print("Connection to wifi: "+self._ssid+" successful...","OK") return True except subprocess.CalledProcessError as e: self.log.print("Error Initiating a new connection with: "+self._ssid+"...",format(e)) return False except Exception as e: self.log.print("Unable to connect...",e) return False def disconnect(self): try: self.log.print("Disconnecting from the current wifi network...","OK") ps = subprocess.Popen(['killall','wpa_supplicant'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) time.sleep(5) return True except Exception as e: self.log.print("Unable to disconnect...",e) return False def status(self): try: flag=False self.log.print("Checking for wifi status...","OK") ps = subprocess.Popen(['iw',self._interface,'link'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for line in ps.stdout: row = line.decode() row = row.replace('\t','') row = row.replace('\n','') row = row.split(' ') if(row[0]=='Not'): self.log.print(self._interface+" not connected to any wifi",row[0]+" "+row[1]) return -1 if(row[0]=='Connected'): flag=True continue if(flag): flag=False ssid='' for r in row: if(r=='SSID:'): continue ssid=ssid+' '+r if(ssid[1:]==self._ssid): self.log.print(self._interface+" connected to...",ssid[1:]) return 1 else: self.log.print(self._interface+" connected to...",ssid[1:]) return 0 #output = subprocess.check_output(('grep', self._ssid), stdin=ps.stdout) #self.log.print("Wifi SSID: "+self._ssid+" found...",(output.decode()).replace('\n','')) #return True except subprocess.CalledProcessError as e: self.log.print(self._interface+" not connected to: "+self._ssid+"...",format(e)) return 0 except Exception as e: self.log.print(self._interface+" not connected to: "+self._ssid+"...",e) return 0 def scan(self): try: self.log.print("Checking the availabilitly of "+self._ssid+"...","OK") ps = subprocess.Popen(['iw',self._interface,'scan'],stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for line in ps.stdout: #print(line.decode()) if('command failed: Network is down (-100)' in line.decode()): self.log.print("Wireless Interface "+self._interface+" down...","OK") pps = subprocess.Popen(['ip','link','set',self._interface,'up'],stdout=subprocess.PIPE, stderr=subprocess.STDOUT) time.sleep(5) self.log.print("Enabling Wireless Interface "+self._interface+" up...","OK") return False else: break output = subprocess.check_output(('grep', 'SSID'), stdin=ps.stdout) for line in (output.decode()).split('\n'): row = line.replace('\t','') row = row.split(': ') if(row[1]==self._ssid): self.log.print("ESSID "+self._ssid+" found...","OK") return True return False except subprocess.CalledProcessError as e: self.log.print("Unable to find: "+self._ssid+"...",format(e)) return False except Exception as e: self.log.print("Unable to find: "+self._ssid+"...",format(e)) return False def write_config(self,data): try: buf='' if(isfile(self._wpa_supplicant)): with open(self._wpa_supplicant,'r') as cfile: for fline in cfile: if('network' in fline): break buf=buf+fline with open(self._wpa_supplicant,'w') as conf: conf.write(buf+data) return True else: self.log.print("Unable to find: "+self._wpa_supplicant+"...",e) return False return True except Exception as e: self.log.print("Unable to write: "+self._wpa_supplicant+"...",format(e)) return False
class Subscriber(): def __init__(self, api, name, version, host, port, username, password, lock): self._api = api self._name = name self._version = version self._host = host self._port = port self._username = username self._password = password self._CLEAN_SESSION = True self._loop_flag = 0 self._lock = lock self.log = Log() self.mapper = Mapper(name, version, api) def start(self): client = mqtt.Client("global_subscriber", clean_session=self._CLEAN_SESSION) client.on_connect = self.on_connect client.on_disconnect = self.on_disconnect client.on_subscribe = self.on_subscribe client.on_unsubscribe = self.on_unsubscribe client.on_message = self.on_message if (self._username != None): client.username_pw_set(username=self._username, password=self._password) client.connect(self._host, port=self._port, keepalive=60, bind_address="") client.loop_start() topic = self._version + "/" + self._name + "/#" r = client.subscribe(topic, self._api.qos()) if r[0] == 0: self.log.print("Global Listener on topic: " + topic, "OK") else: self.log.print( "Global Listener unable to subscribe to topic: " + topic, str(r)) while (self._loop_flag == 0): time.sleep(0.01) client.loop_stop() client.disconnect() self.log.print("Destroying Subscriber Thread", "OK") def on_connect(self, client, userdata, flags, rc): self.log.print( client.name + ":on_connect callback result, Flags: " + str(flags), str(rc)) def on_disconnect(self): pass def on_subscribe(self, client, userdata, mid, granted_qos): self.log.print( client.name + ":on_subscribe callback result, MID: " + str(mid), str(rc)) def on_unsubscribe(self, client, userdata, mid): pass def on_message(self, client, userdata, message): if ('response' in str(message.topic)): return 0 self.log.print("on_message callback, acquiring lock", "OK") self._lock.acquire() try: self.log.print( "incoming request on topic:" + str(message.topic) + " QoS:" + str(message.qos) + " Retain Flag:" + str(message.retain), "OK") self._loop_flag = self.mapper.map(str(message.topic), message.payload.decode()) except Exception as e: self.log.print("on_message callback error", format(e)) self._loop_flag = 0 self.log.print("exiting on_message callback, releasing lock", "OK") self._lock.release()