Skip to content

Commit

Permalink
Merge pull request #25 from Scratchcat1/Flask-Server
Browse files Browse the repository at this point in the history
Flask server
  • Loading branch information
Scratchcat1 authored Jan 18, 2018
2 parents c3d9856 + 17c685c commit c497fa7
Show file tree
Hide file tree
Showing 175 changed files with 29,823 additions and 331 deletions.
3 changes: 3 additions & 0 deletions AATC_AStar.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ def Size(self,xSize,ySize,zSize):

def Get_Size(self):
return self._xSize, self._ySize, self._zSize

def Get_Count(self):
return self._xCount, self._yCount, self._zCount

def add_node(self,node):
self._Nodes[node.Get_NodeID()] = node
Expand Down
2 changes: 1 addition & 1 deletion AATC_Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def GetUserID(self,Username):
def GetUsername(self,UserID):
self.Send("GetUsername",(UserID,))
Sucess,Message,Username = self.Recv()
return Sucess,Message,Username #Username will be ["asfgg"] as it is how database returns it
return Sucess,Message,Username

def AddUser(self,Username,Password):
self.Send("AddUser",(Username,Password))
Expand Down
4 changes: 4 additions & 0 deletions AATC_Config.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
#Control at which setting the server will raise an error if the cost for entering that node sector exceeds value. To prevent selecting a blocked node as a target node to bypass search algorithm.
NOFLYZONE_THRESHOLD_COST = 50

#NoFlyZoneGrapher
NOFLYZONEGRAPHER_FLUSH_GRAPH_NUMBER = 50000 # This controls how frequently while generating the new node costs the no fly zone grapher should flush the graph to reduce memoryu usage.

#OWM Controls
ENABLE_FINE_SPEED_ESTIMATION = False #Allows fine grained estimation of drone speed due to wind. Noticable slowdown when creating flight due to many requests which may be limited by OWM depending on contract
OWM_SLEEP_TIME = 1/60*60*4 # How long the add flight program should sleep between requests to reduce the chance of overusing requests. 1/REQUESTS_PER_MINUTE*60*NUMBER_OF_CONCURRENT_SEARCHES should ensure that the program never hits the limit of OWM.
OWM_API_KEY = '5b943c4857a45d75ef7ee9b301666fa8' #Contains the API key for the OWM
37 changes: 23 additions & 14 deletions AATC_DB.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,16 @@ class DBConnection:
"""


def __init__(self,DatabaseName = "Main.db"):
print("Initializing database connection '",DatabaseName,"'")
def __init__(self):
print("Initializing database connection ")
self._db_con = sql.connect("localhost","AATC_Server","password","AATC_Database")
self._cur = self._db_con.cursor()
self._cur_header = self._db_con.cursor()

def Exit(self):
self._db_con.close()
def Table_Headers(self,TableName):
self._cur_header.execute("SHOW COLUMNS FROM "+ TableName)
self._cur_header.execute("SHOW COLUMNS FROM "+ TableName) # Cannot use placeholders when referencing the table name , syntax error
result = self._cur_header.fetchall()
Headers = []
for item in result:
Expand Down Expand Up @@ -328,7 +328,7 @@ def MonitorChangePassword(self,MonitorID,OldPassword,NewPassword):
return False, "Incorrect old password"

def GetMonitorDrones(self,MonitorID):
self._cur.execute("SELECT Drone.* FROM Drone,MonitorPermission WHERE Drone.UserID = MonitorPermission.UserID and MonitorPermission.MonitorID = %s",(MonitorID,))
self._cur.execute("SELECT Drone.* FROM Drone,MonitorPermission WHERE Drone.UserID = MonitorPermission.UserID AND MonitorPermission.MonitorID = %s",(MonitorID,))
self._db_con.commit()
return True,str(self.Table_Headers("Drone")),self._cur.fetchall()

Expand All @@ -345,11 +345,8 @@ def GetMonitorFlightWaypoints(self,MonitorID):
def GetMonitorID(self,MonitorName):
self._cur.execute("SELECT MonitorID FROM Monitor WHERE MonitorName = %s",(MonitorName,))
result = self._cur.fetchall()
if len(result) != 0:
Sucess = True
else:
Sucess = False
return Sucess,"['MonitorID']",result
return True,"['MonitorID']",result

def GetMonitorName(self,MonitorID):
self._cur.execute("SELECT MonitorName FROM Monitor WHERE MonitorID = %s",(MonitorID,))
return True,"['MonitorName']",self._cur.fetchall()
Expand Down Expand Up @@ -491,28 +488,40 @@ def Bot_GetUserID(self,chat_id):
##########################################################################

def ResetDatabase(self):
self._cur.execute("SET FOREIGN_KEY_CHECKS = 0")
self._cur.execute("SET FOREIGN_KEY_CHECKS = 0") #Otherwise dropping tables will raise errors.
TABLES = ["User","Drone","Monitor","MonitorPermission","Flight","FlightWaypoints","NoFlyZone","DroneCredentials","InputStack","Sessions"]
for item in TABLES:
for item in TABLES: # Drops all tables
self._cur.execute("DROP TABLE IF EXISTS {0}".format(item))

self._cur.execute("CREATE TABLE User(UserID INTEGER PRIMARY KEY AUTO_INCREMENT, Username TEXT,Password TEXT, PublicVisibleFlights INT, PermissionAdder INT , ZoneCreatorPermission INT, ZoneRemoverPermission INT,ZoneModifierPermission INT)")
self._cur.execute("CREATE TABLE Drone(DroneID INTEGER PRIMARY KEY AUTO_INCREMENT, UserID INT, DroneName TEXT, DroneType TEXT, DroneSpeed INT, DroneRange INT, DroneWeight REAL, FlightsFlown INT, LastCoords TEXT, LastBattery REAL)")
self._cur.execute("CREATE TABLE Monitor(MonitorID INTEGER PRIMARY KEY AUTO_INCREMENT, MonitorName TEXT, MonitorPassword TEXT)")
self._cur.execute("CREATE TABLE MonitorPermission(MonitorID INT ,UserID INT, LastAccessed TEXT, ExpiryDate TEXT,PRIMARY KEY(MonitorID,UserID),FOREIGN KEY(MonitorID) REFERENCES Monitor(MonitorID))")
self._cur.execute("CREATE TABLE Flight(FlightID INTEGER PRIMARY KEY AUTO_INCREMENT, DroneID INT, StartCoords TEXT, EndCoords TEXT, StartTime REAL, ETA REAL, EndTime REAL, Distance REAL,XOffset REAL , YOffset REAL , ZOffset REAL,Completed INT)")
self._cur.execute("CREATE TABLE FlightWaypoints(FlightID INT, WaypointNumber INT, Coords TEXT, ETA REAL, BlockTime INT)")
self._cur.execute("CREATE TABLE FlightWaypoints(FlightID INT, WaypointNumber INT, Coords TEXT, ETA REAL, BlockTime INT ,PRIMARY KEY(FlightID,WaypointNumber))")
self._cur.execute("CREATE TABLE NoFlyZone(ZoneID INTEGER PRIMARY KEY AUTO_INCREMENT, StartCoord TEXT, EndCoord TEXT, Level INT, OwnerUserID INT)")
self._cur.execute("CREATE TABLE DroneCredentials(DroneID INTEGER PRIMARY KEY AUTO_INCREMENT ,DronePassword TEXT)")

self._cur.execute("CREATE TABLE InputStack(chat_id INT , stack_pos INT, value TEXT)")
self._cur.execute("CREATE TABLE InputStack(chat_id INT , stack_pos INT, value TEXT, PRIMARY KEY(chat_id,stack_pos))")
self._cur.execute("CREATE TABLE Sessions(chat_id INT PRIMARY KEY, UserID INT)")

self._cur.execute("SET FOREIGN_KEY_CHECKS = 1")
self._cur.execute("SET FOREIGN_KEY_CHECKS = 1") # Reenables checks
self._db_con.commit()



#Pre Primary/Forigen key thing
##self._cur.execute("CREATE TABLE User(UserID INTEGER PRIMARY KEY AUTO_INCREMENT, Username TEXT,Password TEXT, PublicVisibleFlights INT, PermissionAdder INT , ZoneCreatorPermission INT, ZoneRemoverPermission INT,ZoneModifierPermission INT)")
##self._cur.execute("CREATE TABLE Drone(DroneID INTEGER PRIMARY KEY AUTO_INCREMENT, UserID INT, DroneName TEXT, DroneType TEXT, DroneSpeed INT, DroneRange INT, DroneWeight REAL, FlightsFlown INT, LastCoords TEXT, LastBattery REAL)")
##self._cur.execute("CREATE TABLE Monitor(MonitorID INTEGER PRIMARY KEY AUTO_INCREMENT, MonitorName TEXT, MonitorPassword TEXT)")
##self._cur.execute("CREATE TABLE MonitorPermission(MonitorID INT ,UserID INT, LastAccessed TEXT, ExpiryDate TEXT,PRIMARY KEY(MonitorID,UserID),FOREIGN KEY(MonitorID) REFERENCES Monitor(MonitorID))")
##self._cur.execute("CREATE TABLE Flight(FlightID INTEGER PRIMARY KEY AUTO_INCREMENT, DroneID INT, StartCoords TEXT, EndCoords TEXT, StartTime REAL, ETA REAL, EndTime REAL, Distance REAL,XOffset REAL , YOffset REAL , ZOffset REAL,Completed INT)")
##self._cur.execute("CREATE TABLE FlightWaypoints(FlightID INT, WaypointNumber INT, Coords TEXT, ETA REAL, BlockTime INT)")
##self._cur.execute("CREATE TABLE NoFlyZone(ZoneID INTEGER PRIMARY KEY AUTO_INCREMENT, StartCoord TEXT, EndCoord TEXT, Level INT, OwnerUserID INT)")
##self._cur.execute("CREATE TABLE DroneCredentials(DroneID INTEGER PRIMARY KEY AUTO_INCREMENT ,DronePassword TEXT)")
##
##self._cur.execute("CREATE TABLE InputStack(chat_id INT , stack_pos INT, value TEXT)")
##self._cur.execute("CREATE TABLE Sessions(chat_id INT PRIMARY KEY, UserID INT)")



Expand Down
8 changes: 4 additions & 4 deletions AATC_Drone_Logic.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import AATC_Drone,threading,queue,math,time,AATC_GPIO,random, AATC_Config
import AATC_Drone,threading,queue,time,AATC_GPIO,random, AATC_Config
import AATC_Coordinate

class DroneLogicSystem:
Expand Down Expand Up @@ -65,7 +65,7 @@ def CheckForFlight(self):

FlightID = FlightID[0][0]
print("Obtaining flight and drone information. FlightID :",FlightID)
DroneInfo, Flight, Waypoints = GetAllFlightInfo(self._D,self._DroneID,FlightID)
DroneInfo, Flight, Waypoints = GetAllFlightInfo(self._D,FlightID)

self._FlightQueue.put((False,(DroneInfo,Flight,Waypoints)))

Expand All @@ -91,13 +91,13 @@ def RunFlight(self):



def GetAllFlightInfo(D,DRONEID,FlightID): #Gets all drone flight information and packages the information into objects
def GetAllFlightInfo(D,FlightID): #Gets all drone flight information and packages the information into objects
DSucess,DroneMessage,DroneData = D.DroneGetDroneInfo()
FSucess,FlightMessage,FlightData = D.GetFlight(FlightID)
WSucess,WaypointsMessage,FlightWaypointsData = D.GetFlightWaypoints(FlightID)
if not (DSucess and FSucess and WSucess):
print(DroneMessage,FlightMessage,WaypointsMessage)
raise Exception("FlightData or FlightWaypointData was not sucessfully obtained")
raise Exception("FlightData or FlightWaypointData or DroneData was not sucessfully obtained")

DroneInfo = AATC_Drone.MakeDroneInfo(DroneMessage, DroneData)
Flight = AATC_Drone.GetFlightObject(FlightMessage,FlightData)
Expand Down
4 changes: 2 additions & 2 deletions AATC_GPIO.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def GPIO_Thread(Thread_Name,GPIO_Queue):
if not Repeat:
Function,FuncArgs = BlankFunction,() #Resets commands. Allows function to exit itself.

if not GPIO_Queue.empty():
while not GPIO_Queue.empty(): #While loop implemented so that if many commands are send per loop they will all be processed.
Data = GPIO_Queue.get()
#GPIO_Queue.task_done()
Command,Arguments = Data[0],Data[1]
Expand Down Expand Up @@ -133,7 +133,7 @@ def Main(self):
self.Reset(*Args)

else:
self.PassData(Request[0],(Request[1],Request[2]))
self.PassData(Request[0],Request[1:])


except Exception as e:
Expand Down
33 changes: 22 additions & 11 deletions AATC_NoFlyZoneGrapher.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import AATC_DB,AATC_AStar,ast,time
from AATC_Coordinate import *
import AATC_DB,AATC_AStar,ast,time,AATC_Config,AATC_Coordinate

def NoFlyZoneGrapher_Launch(Thread_Name,Thread_Queue,Interval = 36000):
NFZG = NoFlyZoneGrapher(Thread_Name,Thread_Queue,Interval)
NFZG.Main_Loop()

class NoFlyZoneGrapher:
""" Selects all NoFlyZones, calculates the nodes which they correspond to and modifies the cost of those nodes
Expand All @@ -8,7 +11,7 @@ class NoFlyZoneGrapher:
Then for all nodes, the node is loaded, cost modified
Then graph is saved
Repeats every interval seconds.
Must load entire graph and all NoFlyZones at once as if a NoFlyZone is removed there may be other smaller NoFlyZones which affect the cost of the node.
Must load entire graph and all NoFlyZones at once as if a NoFlyZone is removed there may be other smaller NoFlyZones which affect the cost of the node. #DEALT WITH , DONE IN GROUPS
Very RAM intensive. Could be run on a different device and update via a network share.
Could use an A/B method to update if file locking occurs where the Updating takes place on one set of data while the other set of data is read from by eg A* pathfinding
Expand All @@ -24,7 +27,7 @@ def __init__(self,Thread_Name,Thread_Queue,Interval = 36000):
self._xSize,self._ySize,self._zSize = graph.Get_Size()
del graph

self.Main_Loop()


def Main_Loop(self):
self._Exit = False
Expand Down Expand Up @@ -69,8 +72,8 @@ def GetNoFlyZones(self):
for line in Data: #Converts each line into a dict with the column name as a key
lineDict = {
"ZoneID":line[ZoneIDIndex],
"StartCoord":Coordinate(*ast.literal_eval(line[StartCoordIndex])),
"EndCoord":Coordinate(*ast.literal_eval(line[EndCoordIndex])),
"StartCoord":AATC_Coordinate.Coordinate(*ast.literal_eval(line[StartCoordIndex])),
"EndCoord":AATC_Coordinate.Coordinate(*ast.literal_eval(line[EndCoordIndex])),
"Level":line[LevelIndex],
"OwnerUserID":line[OwnerUserIDIndex]}
ProcessedData.append(lineDict) #Also turns sthe coords into objects rather than strings
Expand Down Expand Up @@ -99,20 +102,28 @@ def Make_Values(self,NoFlyZoneData,ABSlot = 1):

Values[NodeID] = v #This gets the maximum cost for that node

######MODIFY TO BE OK
graph.Node_Cache = {} #Reduces memory usage.
## ######MODIFY TO BE OK
## graph.Node_Cache = {} #Reduces memory usage.
graph.FlushGraph() #Reduces memory usage by removing the Node_Caches


print("[NoFlyZoneGrapher] Length of Values:",len(Values))
for NodeID in list(Values.keys()): #CHECK THIS. Only using those involved with a new no fly zone may cause issues if a no fly zone was removed. Maybe should be set to all node IDs.
for NodeID in graph.All_NodeIDs(): #CHECK THIS. Only using those involved with a new no fly zone may cause issues if a no fly zone was removed. Maybe should be set to all node IDs.
node = graph.GetNode(NodeID)
if node.Get_NodeID() in Values:
node.Set_Cost( Values[node.Get_NodeID()])
Values.pop(node.Get_NodeID())# Reduce memory usage by evicting Node values which have been added already
else:
node.Set_Cost(1)
if NodeID % AATC_Config.NOFLYZONEGRAPHER_FLUSH_GRAPH_NUMBER == 0: #Every N nodes the program will save the current nodes and remove them from memory
try:
graph.SaveNodes([graph.CurrentFolderName()]) #Ensures any loaded nodes are saved. As all nodes in a block are loaded , entire blocks are saved thus no nodes are lost.
except Exception as e:
print("Error saving nodes",e," Most likely no NoFlyZoneData yet")
graph.FlushGraph() #The graph nodes are then emptied to reduce memory usage.
#print("Processede block to ",NodeID)

try:
graph.SaveNodes([graph.CurrentFolderName()])
graph.SaveNodes([graph.CurrentFolderName()]) #Saves any last nodes.
except Exception as e:
print("Error saving nodes",e," Most likely no NoFlyZoneData yet")

Expand Down
28 changes: 14 additions & 14 deletions AATC_Server_002.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
def GetTime():
return int(time.time())

def CoordLessThanOrEqual(Coord1,Coord2):# True if Coord1 <= Coord2
List1 = list(Coord1)
List2 = list(Coord2)
BoolList = []
for x in range(len(List1)): #Goes through each item in the lists
if List1[x] <= List2[x]: #If The Coord1[x] <= Coord2[x]
BoolList.append(True)
else:
BoolList.append(False)
return all(BoolList)
##def CoordLessThanOrEqual(Coord1,Coord2):# True if Coord1 <= Coord2
## List1 = list(Coord1)
## List2 = list(Coord2)
## BoolList = []
## for x in range(len(List1)): #Goes through each item in the lists
## if List1[x] <= List2[x]: #If The Coord1[x] <= Coord2[x]
## BoolList.append(True)
## else:
## BoolList.append(False)
## return all(BoolList)



Expand Down Expand Up @@ -368,15 +368,15 @@ def AddFlight(self,Arguments):
DroneSpeed,DroneRange = DroneData[SpeedIndex],DroneData[RangeIndex]

Weather_Estimator = AATC_Weather.OWM_Control()
Estimated_Drone_Speed = Weather_Estimator.Get_Ajusted_Speed(CoordList[0]["Coords"],CoordList[-1]["Coords"],DroneSpeed,Time)
Estimated_Drone_Speed = Weather_Estimator.Get_Adjusted_Speed(CoordList[0]["Coords"],CoordList[-1]["Coords"],DroneSpeed,Time)
TotalDistance = 0
for x in range(len(CoordList)):
if x != 0: #If not first Coord add the difference in distance to time etc
Distance = DeltaCoordToMetres(CoordList[x]["Coords"],CoordList[x-1]["Coords"]) #Gets distance in metres
TotalDistance += Distance

if AATC_Config.ENABLE_FINE_SPEED_ESTIMATION:
Estimated_Drone_Speed = Weather_Estimator.Get_Ajusted_Speed(CoordList[x]["Coords"],CoordList[x-1]["Coords"],DroneSpeed,Time)
Estimated_Drone_Speed = Weather_Estimator.Get_Adjusted_Speed(CoordList[x]["Coords"],CoordList[x-1]["Coords"],DroneSpeed,Time)
time.sleep(AATC_Config.OWM_SLEEP_TIME)
DeltaTime = Distance/Estimated_Drone_Speed
Time = Time + DeltaTime
Expand Down Expand Up @@ -498,12 +498,12 @@ def Main(self,Command,Arguments):

except Exception as e:
Sucess,Message,Data = False,"An Error occured"+str(e),[]
print("Error occured with UserID:",str(self._ClientID),". Error :",str(e),". Sending failure message")
print("Error occured with ",self._Thread_Name,". Error :",str(e),". Sending failure message")

try:
self.Send((Sucess,Message,Data))
except Exception as e:
print("Error sending message back to chat",e)
print(self._Thread_Name,"Error sending message back to chat",e)
self._DB.Exit()


Expand Down
16 changes: 11 additions & 5 deletions AATC_Server_Starter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import multiprocessing,socket,AATC_NoFlyZoneGrapher,sys,time,AATC_GPIO,HedaBot
import AATC_Server_002 as AATC_Server
from AATC_Coordinate import *
#from AATC_Coordinate import *
from flask_app import Flask_Test_App


def UserProcessSpawner():
Expand Down Expand Up @@ -114,6 +115,12 @@ def MakeDroneConnection(Thread_Name,Thread_Queue,conn):


##########################################################
#####################This section is part of the flask webserver component of the AATC program, not part of the main project.

def StartFlaskServer(Thread_Name,Thread_Queue):
Flask_Test_App.main_app(Flask_Test_App.app) # Starts the flask webserver


##########################################################


Expand Down Expand Up @@ -168,21 +175,20 @@ def StartProcesses(Control_Queue):
Control_Queue.put(("Controller","Create_Process",("DSpawner",ProcessSpawner,(8002,"Drone",MakeDroneConnection))))


Control_Queue.put(("Controller","Create_Process",("Grapher",AATC_NoFlyZoneGrapher.NoFlyZoneGrapher)))
Control_Queue.put(("Controller","Create_Process",("Grapher",AATC_NoFlyZoneGrapher.NoFlyZoneGrapher_Launch)))
Control_Queue.put(("Controller","Create_Process",("Cleaner",AATC_Server.Cleaner)))

Control_Queue.put(("Controller","Create_Process",("Hedabot",HedaBot.TelebotLaunch,())))
###Control_Queue.put(("Controller","Create_Process",("Flask_Server",StartFlaskServer,())))
print("[StartProcesses] All processes started")


if __name__ == "__main__":
print("Server is starting")




Control_Queue = AATC_GPIO.Create_Controller()
StartProcesses(Control_Queue)


Main_Command = ""
while Main_Command != "EXIT":
Expand Down
Binary file added CAStar/CAStar.pyd
Binary file not shown.
Loading

0 comments on commit c497fa7

Please sign in to comment.