Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
D
df-aggregator
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Oleksandr Barabash
df-aggregator
Commits
0c39414f
Commit
0c39414f
authored
Oct 06, 2021
by
Corey Koval
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Python Style Improvments
parent
0cb63865
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
203 additions
and
127 deletions
+203
-127
df-aggregator.py
df-aggregator.py
+203
-127
No files found.
df-aggregator.py
View file @
0c39414f
...
@@ -30,11 +30,11 @@ from os import system, name, kill, getpid
...
@@ -30,11 +30,11 @@ from os import system, name, kill, getpid
from
lxml
import
etree
from
lxml
import
etree
from
sklearn.cluster
import
DBSCAN
from
sklearn.cluster
import
DBSCAN
from
sklearn.preprocessing
import
StandardScaler
,
minmax_scale
from
sklearn.preprocessing
import
StandardScaler
,
minmax_scale
from
geojson
import
Point
,
MultiPoint
,
Feature
,
FeatureCollection
from
geojson
import
MultiPoint
,
Feature
,
FeatureCollection
from
czml3
import
Packet
,
Document
,
Preamble
from
czml3
import
Packet
,
Document
,
Preamble
from
czml3.properties
import
Position
,
Polyline
,
PolylineOutlineMaterial
,
Color
,
Material
from
czml3.properties
import
Position
,
Polyline
,
PolylineOutlineMaterial
,
Color
,
Material
from
multiprocessing
import
Process
,
Queue
from
multiprocessing
import
Process
,
Queue
from
bottle
import
route
,
run
,
request
,
get
,
p
ost
,
p
ut
,
response
,
redirect
,
template
,
static_file
from
bottle
import
route
,
run
,
request
,
get
,
put
,
response
,
redirect
,
template
,
static_file
from
bottle.ext.websocket
import
GeventWebSocketServer
,
websocket
from
bottle.ext.websocket
import
GeventWebSocketServer
,
websocket
from
sys
import
version_info
from
sys
import
version_info
...
@@ -51,10 +51,11 @@ DBSCAN_WAIT_Q = Queue()
...
@@ -51,10 +51,11 @@ DBSCAN_WAIT_Q = Queue()
DATABASE_EDIT_Q
=
Queue
()
DATABASE_EDIT_Q
=
Queue
()
DATABASE_RETURN
=
Queue
()
DATABASE_RETURN
=
Queue
()
d
=
40000
#
draw distance of LOBs in meters
d
=
40000
#
draw distance of LOBs in meters
max_age
=
5000
max_age
=
5000
receivers
=
[]
receivers
=
[]
###############################################
###############################################
# Stores settings realted to intersect capture
# Stores settings realted to intersect capture
# and post-processing.
# and post-processing.
...
@@ -69,6 +70,7 @@ class math_settings:
...
@@ -69,6 +70,7 @@ class math_settings:
receiving
=
True
receiving
=
True
plotintersects
=
False
plotintersects
=
False
################################################
################################################
# Stores all variables pertaining to a reveiver.
# Stores all variables pertaining to a reveiver.
# Also updates receiver variable upon request.
# Also updates receiver variable upon request.
...
@@ -130,17 +132,18 @@ class receiver:
...
@@ -130,17 +132,18 @@ class receiver:
self
.
doa_time
=
0
self
.
doa_time
=
0
self
.
isActive
=
False
self
.
isActive
=
False
print
(
ex
)
print
(
ex
)
print
(
f
"Problem connecting to {self.station_url}, receiver deactivated. Reactivate in WebUI."
)
print
(
f
"Problem connecting to {self.station_url}, receiver deactivated. Reactivate in WebUI."
)
# raise IOError
# raise IOError
# Returns receivers properties as a dict, useful for passing data to the WebUI
# Returns receivers properties as a dict, useful for passing data to the WebUI
def
receiver_dict
(
self
):
def
receiver_dict
(
self
):
return
({
'station_id'
:
self
.
station_id
,
'station_url'
:
self
.
station_url
,
return
({
'station_id'
:
self
.
station_id
,
'station_url'
:
self
.
station_url
,
'latitude'
:
self
.
latitude
,
'longitude'
:
self
.
longitude
,
'heading'
:
self
.
heading
,
'latitude'
:
self
.
latitude
,
'longitude'
:
self
.
longitude
,
'heading'
:
self
.
heading
,
'doa'
:
self
.
doa
,
'frequency'
:
self
.
frequency
,
'power'
:
self
.
power
,
'doa'
:
self
.
doa
,
'frequency'
:
self
.
frequency
,
'power'
:
self
.
power
,
'confidence'
:
self
.
confidence
,
'doa_time'
:
self
.
doa_time
,
'mobile'
:
self
.
isMobile
,
'confidence'
:
self
.
confidence
,
'doa_time'
:
self
.
doa_time
,
'mobile'
:
self
.
isMobile
,
'active'
:
self
.
isActive
,
'auto'
:
self
.
isAuto
,
'inverted'
:
self
.
inverted
,
'active'
:
self
.
isActive
,
'auto'
:
self
.
isAuto
,
'inverted'
:
self
.
inverted
,
'single'
:
self
.
isSingle
})
'single'
:
self
.
isSingle
})
def
lob_length
(
self
):
def
lob_length
(
self
):
if
self
.
d_2_last_intersection
:
if
self
.
d_2_last_intersection
:
...
@@ -163,6 +166,7 @@ class receiver:
...
@@ -163,6 +166,7 @@ class receiver:
last_processed_at
=
0
last_processed_at
=
0
d_2_last_intersection
=
[
d
]
d_2_last_intersection
=
[
d
]
###############################################
###############################################
# Converts Lat/Lon to polar coordinates
# Converts Lat/Lon to polar coordinates
###############################################
###############################################
...
@@ -183,10 +187,11 @@ def plot_polar(lat_a, lon_a, lat_a2, lon_a2):
...
@@ -183,10 +187,11 @@ def plot_polar(lat_a, lon_a, lat_a2, lon_a2):
return
([
x1
,
y1
,
z1
],
[
x2
,
y2
,
z2
])
return
([
x1
,
y1
,
z1
],
[
x2
,
y2
,
z2
])
#####################################################
#####################################################
# Find line of intersection between two great circles
# Find line of intersection between two great circles
#####################################################
#####################################################
def
plot_intersects
(
lat_a
,
lon_a
,
doa_a
,
lat_b
,
lon_b
,
doa_b
,
max_distance
=
100000
):
def
plot_intersects
(
lat_a
,
lon_a
,
doa_a
,
lat_b
,
lon_b
,
doa_b
,
max_distance
=
100000
):
# plot another point on the lob
# plot another point on the lob
# v.direct(lat_a, lon_a, doa_a, d)
# v.direct(lat_a, lon_a, doa_a, d)
# returns (lat_a2, lon_a2)
# returns (lat_a2, lon_a2)
...
@@ -205,16 +210,18 @@ def plot_intersects(lat_a, lon_a, doa_a, lat_b, lon_b, doa_b, max_distance = 100
...
@@ -205,16 +210,18 @@ def plot_intersects(lat_a, lon_a, doa_a, lat_b, lon_b, doa_b, max_distance = 100
# Find two intersection points
# Find two intersection points
X1
=
L
/
np
.
sqrt
(
L
[
0
]
**
2
+
L
[
1
]
**
2
+
L
[
2
]
**
2
)
X1
=
L
/
np
.
sqrt
(
L
[
0
]
**
2
+
L
[
1
]
**
2
+
L
[
2
]
**
2
)
X2
=
-
X1
X2
=
-
X1
mag
=
lambda
q
:
np
.
sqrt
(
np
.
vdot
(
q
,
q
))
dist1
=
mag
(
X1
-
plane_a
[
0
])
def
mag
(
q
):
dist2
=
mag
(
X2
-
plane_a
[
0
])
return
np
.
sqrt
(
np
.
vdot
(
q
,
q
))
#return the (lon_lat pair of the closer intersection)
dist1
=
mag
(
X1
-
plane_a
[
0
])
dist2
=
mag
(
X2
-
plane_a
[
0
])
# return the (lon_lat pair of the closer intersection)
if
dist1
<
dist2
:
if
dist1
<
dist2
:
i_lat
=
math
.
asin
(
X1
[
2
])
*
180.
/
np
.
pi
i_lat
=
math
.
asin
(
X1
[
2
])
*
180.
/
np
.
pi
i_long
=
math
.
atan2
(
X1
[
1
],
X1
[
0
])
*
180.
/
np
.
pi
i_long
=
math
.
atan2
(
X1
[
1
],
X1
[
0
])
*
180.
/
np
.
pi
else
:
else
:
i_lat
=
math
.
asin
(
X2
[
2
])
*
180.
/
np
.
pi
i_lat
=
math
.
asin
(
X2
[
2
])
*
180.
/
np
.
pi
i_long
=
math
.
atan2
(
X2
[
1
],
X2
[
0
])
*
180.
/
np
.
pi
i_long
=
math
.
atan2
(
X2
[
1
],
X2
[
0
])
*
180.
/
np
.
pi
check_bearing
=
v
.
get_heading
((
lat_a
,
lon_a
),
(
i_lat
,
i_long
))
check_bearing
=
v
.
get_heading
((
lat_a
,
lon_a
),
(
i_lat
,
i_long
))
...
@@ -225,6 +232,7 @@ def plot_intersects(lat_a, lon_a, doa_a, lat_b, lon_b, doa_b, max_distance = 100
...
@@ -225,6 +232,7 @@ def plot_intersects(lat_a, lon_a, doa_a, lat_b, lon_b, doa_b, max_distance = 100
else
:
else
:
return
None
return
None
#######################################################################
#######################################################################
# We start this in it's own process do it doesn't eat all of your RAM.
# We start this in it's own process do it doesn't eat all of your RAM.
# This becomes noticable at over 10k intersections.
# This becomes noticable at over 10k intersections.
...
@@ -236,6 +244,7 @@ def do_dbscan(X, epsilon, minsamp):
...
@@ -236,6 +244,7 @@ def do_dbscan(X, epsilon, minsamp):
if
not
DBSCAN_WAIT_Q
.
empty
():
if
not
DBSCAN_WAIT_Q
.
empty
():
DBSCAN_WAIT_Q
.
get
()
DBSCAN_WAIT_Q
.
get
()
####################################
####################################
# Autocalculate the best eps value.
# Autocalculate the best eps value.
####################################
####################################
...
@@ -267,12 +276,13 @@ def autoeps_calc(X):
...
@@ -267,12 +276,13 @@ def autoeps_calc(X):
except
IndexError
:
except
IndexError
:
return
0
return
0
###############################################
###############################################
# Computes DBSCAN Alorithm is applicable,
# Computes DBSCAN Alorithm is applicable,
# finds the mean of a cluster of intersections.
# finds the mean of a cluster of intersections.
###############################################
###############################################
def
process_data
(
database_name
,
epsilon
,
min_samp
):
def
process_data
(
database_name
,
epsilon
,
min_samp
):
n_std
=
3.0
n_std
=
3.0
intersect_list
=
[]
intersect_list
=
[]
likely_location
=
[]
likely_location
=
[]
ellipsedata
=
[]
ellipsedata
=
[]
...
@@ -292,7 +302,7 @@ def process_data(database_name, epsilon, min_samp):
...
@@ -292,7 +302,7 @@ def process_data(database_name, epsilon, min_samp):
intersect_array
=
np
.
array
(
curs
.
fetchall
())
intersect_array
=
np
.
array
(
curs
.
fetchall
())
if
intersect_array
.
size
!=
0
:
if
intersect_array
.
size
!=
0
:
if
epsilon
!=
"0"
:
if
epsilon
!=
"0"
:
X
=
StandardScaler
()
.
fit_transform
(
intersect_array
[:,
0
:
2
])
X
=
StandardScaler
()
.
fit_transform
(
intersect_array
[:,
0
:
2
])
n_points
=
len
(
X
)
n_points
=
len
(
X
)
if
min_samp
==
"auto"
:
if
min_samp
==
"auto"
:
...
@@ -318,7 +328,7 @@ def process_data(database_name, epsilon, min_samp):
...
@@ -318,7 +328,7 @@ def process_data(database_name, epsilon, min_samp):
print
(
"Waiting for my turn..."
)
print
(
"Waiting for my turn..."
)
time
.
sleep
(
1
)
time
.
sleep
(
1
)
starttime
=
time
.
time
()
starttime
=
time
.
time
()
db
=
Process
(
target
=
do_dbscan
,
args
=
(
X
,
epsilon
,
min_samp
))
db
=
Process
(
target
=
do_dbscan
,
args
=
(
X
,
epsilon
,
min_samp
))
db
.
daemon
=
True
db
.
daemon
=
True
db
.
start
()
db
.
start
()
try
:
try
:
...
@@ -332,7 +342,8 @@ def process_data(database_name, epsilon, min_samp):
...
@@ -332,7 +342,8 @@ def process_data(database_name, epsilon, min_samp):
return
likely_location
,
intersect_list
,
ellipsedata
return
likely_location
,
intersect_list
,
ellipsedata
stoptime
=
time
.
time
()
stoptime
=
time
.
time
()
print
(
f
"DBSCAN took {stoptime - starttime} seconds to compute the clusters."
)
print
(
f
"DBSCAN took {stoptime - starttime} seconds to compute the clusters."
)
intersect_array
=
np
.
column_stack
((
intersect_array
,
labels
))
intersect_array
=
np
.
column_stack
((
intersect_array
,
labels
))
...
@@ -344,33 +355,37 @@ def process_data(database_name, epsilon, min_samp):
...
@@ -344,33 +355,37 @@ def process_data(database_name, epsilon, min_samp):
print
(
'Outliers Removed:
%
d'
%
n_noise_
)
print
(
'Outliers Removed:
%
d'
%
n_noise_
)
for
x
in
range
(
n_clusters_
):
for
x
in
range
(
n_clusters_
):
cluster
=
np
.
array
([])
.
reshape
(
0
,
3
)
cluster
=
np
.
array
([])
.
reshape
(
0
,
3
)
for
y
in
range
(
len
(
intersect_array
)):
for
y
in
range
(
len
(
intersect_array
)):
if
intersect_array
[
y
][
-
1
]
==
x
:
if
intersect_array
[
y
][
-
1
]
==
x
:
cluster
=
np
.
concatenate
((
cluster
,
[
intersect_array
[
y
][
0
:
-
1
]]),
axis
=
0
)
cluster
=
np
.
concatenate
(
(
cluster
,
[
intersect_array
[
y
][
0
:
-
1
]]),
axis
=
0
)
# weighted_location.append(np.average(cluster[:,0:2], weights=cluster[:,2], axis=0).tolist())
# weighted_location.append(np.average(cluster[:,0:2], weights=cluster[:,2], axis=0).tolist())
clustermean
=
np
.
mean
(
cluster
[:,
0
:
2
],
axis
=
0
)
clustermean
=
np
.
mean
(
cluster
[:,
0
:
2
],
axis
=
0
)
likely_location
.
append
(
clustermean
.
tolist
())
likely_location
.
append
(
clustermean
.
tolist
())
cov
=
np
.
cov
(
cluster
[:,
0
],
cluster
[:,
1
])
cov
=
np
.
cov
(
cluster
[:,
0
],
cluster
[:,
1
])
a
=
cov
[
0
,
0
]
a
=
cov
[
0
,
0
]
b
=
cov
[
0
,
1
]
b
=
cov
[
0
,
1
]
c
=
cov
[
1
,
1
]
c
=
cov
[
1
,
1
]
lam1
=
a
+
c
/
2
+
np
.
sqrt
((
a
-
c
/
2
)
**
2
+
b
**
2
)
lam1
=
a
+
c
/
2
+
np
.
sqrt
((
a
-
c
/
2
)
**
2
+
b
**
2
)
lam2
=
a
+
c
/
2
-
np
.
sqrt
((
a
-
c
/
2
)
**
2
+
b
**
2
)
#
lam2 = a+c/2 - np.sqrt((a-c/2)**2 + b**2)
# print([lam1, lam2, a, c])
# print([lam1, lam2, a, c])
pearson
=
b
/
np
.
sqrt
(
a
*
c
)
pearson
=
b
/
np
.
sqrt
(
a
*
c
)
ell_radius_x
=
np
.
sqrt
(
1
+
pearson
)
*
np
.
sqrt
(
a
)
*
n_std
ell_radius_x
=
np
.
sqrt
(
1
+
pearson
)
*
np
.
sqrt
(
a
)
*
n_std
ell_radius_y
=
np
.
sqrt
(
1
-
pearson
)
*
np
.
sqrt
(
c
)
*
n_std
ell_radius_y
=
np
.
sqrt
(
1
-
pearson
)
*
np
.
sqrt
(
c
)
*
n_std
axis_x
=
v
.
inverse
(
clustermean
.
tolist
()[::
-
1
],
(
ell_radius_x
+
clustermean
[
1
],
clustermean
[
0
]))[
0
]
axis_x
=
v
.
inverse
(
clustermean
.
tolist
()[
axis_y
=
v
.
inverse
(
clustermean
.
tolist
()[::
-
1
],
(
clustermean
[
1
],
ell_radius_y
+
clustermean
[
0
]))[
0
]
::
-
1
],
(
ell_radius_x
+
clustermean
[
1
],
clustermean
[
0
]))[
0
]
axis_y
=
v
.
inverse
(
clustermean
.
tolist
()[
::
-
1
],
(
clustermean
[
1
],
ell_radius_y
+
clustermean
[
0
]))[
0
]
if
b
==
0
and
a
>=
c
:
if
b
==
0
and
a
>=
c
:
rotation
=
0
rotation
=
0
elif
b
==
0
and
a
<
c
:
elif
b
==
0
and
a
<
c
:
rotation
=
np
.
pi
/
2
rotation
=
np
.
pi
/
2
else
:
else
:
rotation
=
math
.
atan2
(
lam1
-
a
,
b
)
rotation
=
math
.
atan2
(
lam1
-
a
,
b
)
ellipsedata
.
append
([
axis_x
,
axis_y
,
rotation
,
*
clustermean
.
tolist
()])
ellipsedata
.
append
(
[
axis_x
,
axis_y
,
rotation
,
*
clustermean
.
tolist
()])
for
x
in
likely_location
:
for
x
in
likely_location
:
print
(
x
[::
-
1
])
print
(
x
[::
-
1
])
...
@@ -387,6 +402,7 @@ def process_data(database_name, epsilon, min_samp):
...
@@ -387,6 +402,7 @@ def process_data(database_name, epsilon, min_samp):
conn
.
close
()
conn
.
close
()
return
likely_location
,
intersect_list
,
ellipsedata
return
likely_location
,
intersect_list
,
ellipsedata
#######################################################################
#######################################################################
# Checks interesections stored in the database against a lat/lon/radius
# Checks interesections stored in the database against a lat/lon/radius
# and removes items inside exclusion areas.
# and removes items inside exclusion areas.
...
@@ -412,6 +428,7 @@ def purge_database(type, lat, lon, radius):
...
@@ -412,6 +428,7 @@ def purge_database(type, lat, lon, radius):
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
print
(
f
"I purged {purge_count} intersects."
)
print
(
f
"I purged {purge_count} intersects."
)
###############################################
###############################################
# Checks interesections stored in the database
# Checks interesections stored in the database
# against a lat/lon/radius and removes items
# against a lat/lon/radius and removes items
...
@@ -484,38 +501,44 @@ def run_aoi_rules():
...
@@ -484,38 +501,44 @@ def run_aoi_rules():
print
(
f
"Purged {purged} intersections and sorted {sorted} intersections into {n_aoi} AOIs in {stoptime - starttime} seconds."
)
print
(
f
"Purged {purged} intersections and sorted {sorted} intersections into {n_aoi} AOIs in {stoptime - starttime} seconds."
)
return
"OK"
return
"OK"
###############################################
###############################################
# Writes a geojson file upon request.
# Writes a geojson file upon request.
###############################################
###############################################
def
write_geojson
(
best_point
,
all_the_points
):
def
write_geojson
(
best_point
,
all_the_points
):
all_pt_style
=
{
"name"
:
"Various Intersections"
,
"marker-color"
:
"#FF0000"
}
all_pt_style
=
{
"name"
:
"Various Intersections"
,
"marker-color"
:
"#FF0000"
}
best_pt_style
=
{
"name"
:
"Most Likely TX Location"
,
"marker-color"
:
"#00FF00"
}
best_pt_style
=
{
"name"
:
"Most Likely TX Location"
,
if
all_the_points
!=
None
:
"marker-color"
:
"#00FF00"
}
all_the_points
=
Feature
(
properties
=
all_pt_style
,
geometry
=
MultiPoint
(
tuple
(
all_the_points
)))
if
all_the_points
is
not
None
:
all_the_points
=
Feature
(
properties
=
all_pt_style
,
geometry
=
MultiPoint
(
tuple
(
all_the_points
)))
with
open
(
geofile
,
"w"
)
as
file1
:
with
open
(
geofile
,
"w"
)
as
file1
:
if
best_point
!=
None
:
if
best_point
is
not
None
:
reversed_best_point
=
[]
reversed_best_point
=
[]
for
x
in
best_point
:
for
x
in
best_point
:
reversed_best_point
.
append
(
x
)
reversed_best_point
.
append
(
x
)
best_point
=
Feature
(
properties
=
best_pt_style
,
geometry
=
MultiPoint
(
tuple
(
reversed_best_point
)))
best_point
=
Feature
(
properties
=
best_pt_style
,
geometry
=
MultiPoint
(
file1
.
write
(
str
(
FeatureCollection
([
best_point
,
all_the_points
])))
tuple
(
reversed_best_point
)))
file1
.
write
(
str
(
FeatureCollection
(
[
best_point
,
all_the_points
])))
else
:
else
:
file1
.
write
(
str
(
FeatureCollection
([
all_the_points
])))
file1
.
write
(
str
(
FeatureCollection
([
all_the_points
])))
print
(
f
"Wrote file {geofile}"
)
print
(
f
"Wrote file {geofile}"
)
###############################################
###############################################
# Writes output.czml used by the WebUI
# Writes output.czml used by the WebUI
###############################################
###############################################
def
write_czml
(
best_point
,
all_the_points
,
ellipsedata
,
plotallintersects
,
eps
):
def
write_czml
(
best_point
,
all_the_points
,
ellipsedata
,
plotallintersects
,
eps
):
point_properties
=
{
point_properties
=
{
"pixelSize"
:
5.0
,
"pixelSize"
:
5.0
,
"heightReference"
:
"CLAMP_TO_GROUND"
,
"heightReference"
:
"CLAMP_TO_GROUND"
,
"zIndex"
:
3
"zIndex"
:
3
}
}
best_point_properties
=
{
best_point_properties
=
{
"pixelSize"
:
12.0
,
"pixelSize"
:
12.0
,
"zIndex"
:
10
,
"zIndex"
:
10
,
"heightReference"
:
"CLAMP_TO_GROUND"
,
"heightReference"
:
"CLAMP_TO_GROUND"
,
"color"
:
{
"color"
:
{
"rgba"
:
[
0
,
255
,
0
,
255
],
"rgba"
:
[
0
,
255
,
0
,
255
],
}
}
...
@@ -540,15 +563,17 @@ def write_czml(best_point, all_the_points, ellipsedata, plotallintersects, eps):
...
@@ -540,15 +563,17 @@ def write_czml(best_point, all_the_points, ellipsedata, plotallintersects, eps):
if
len
(
all_the_points
)
>
0
and
(
plotallintersects
or
eps
==
"0"
):
if
len
(
all_the_points
)
>
0
and
(
plotallintersects
or
eps
==
"0"
):
all_the_points
=
np
.
array
(
all_the_points
)
all_the_points
=
np
.
array
(
all_the_points
)
scaled_time
=
minmax_scale
(
all_the_points
[:,
-
1
])
scaled_time
=
minmax_scale
(
all_the_points
[:,
-
1
])
all_the_points
=
np
.
column_stack
((
all_the_points
,
scaled_time
))
all_the_points
=
np
.
column_stack
((
all_the_points
,
scaled_time
))
for
x
in
all_the_points
:
for
x
in
all_the_points
:
# rgb = hsvtorgb(x[-1]/3, 0.9, 0.9)
# rgb = hsvtorgb(x[-1]/3, 0.9, 0.9)
rgb
=
map
(
lambda
x
:
int
(
x
*
255
),
hsv_to_rgb
(
x
[
-
1
]
/
3
,
0.9
,
0.9
))
rgb
=
map
(
lambda
x
:
int
(
x
*
255
),
hsv_to_rgb
(
x
[
-
1
]
/
3
,
0.9
,
0.9
))
color_property
=
{
"color"
:{
"rgba"
:
[
*
rgb
,
255
]}}
color_property
=
{
"color"
:
{
"rgba"
:
[
*
rgb
,
255
]}}
all_point_packets
.
append
(
Packet
(
id
=
str
(
x
[
1
])
+
", "
+
str
(
x
[
0
]),
all_point_packets
.
append
(
Packet
(
id
=
str
(
x
[
1
])
+
", "
+
str
(
x
[
0
]),
point
=
{
**
point_properties
,
**
color_property
},
point
=
{
**
point_properties
,
position
=
{
"cartographicDegrees"
:
[
x
[
0
],
x
[
1
],
0
]},
**
color_property
},
position
=
{
"cartographicDegrees"
:
[
x
[
0
],
x
[
1
],
0
]},
))
))
if
len
(
best_point
)
>
0
:
if
len
(
best_point
)
>
0
:
...
@@ -556,8 +581,7 @@ def write_czml(best_point, all_the_points, ellipsedata, plotallintersects, eps):
...
@@ -556,8 +581,7 @@ def write_czml(best_point, all_the_points, ellipsedata, plotallintersects, eps):
gmaps_url
=
f
"https://www.google.com/maps/dir/?api=1&destination={x[1]},+{x[0]}&travelmode=driving"
gmaps_url
=
f
"https://www.google.com/maps/dir/?api=1&destination={x[1]},+{x[0]}&travelmode=driving"
best_point_packets
.
append
(
Packet
(
id
=
str
(
x
[
1
])
+
", "
+
str
(
x
[
0
]),
best_point_packets
.
append
(
Packet
(
id
=
str
(
x
[
1
])
+
", "
+
str
(
x
[
0
]),
point
=
best_point_properties
,
point
=
best_point_properties
,
description
=
description
=
f
"<a href='{gmaps_url}' target='_blank'>Google Maps Directions</a>"
,
f
"<a href='{gmaps_url}' target='_blank'>Google Maps Directions</a>"
,
position
=
{
"cartographicDegrees"
:
[
x
[
0
],
x
[
1
],
0
]}))
position
=
{
"cartographicDegrees"
:
[
x
[
0
],
x
[
1
],
0
]}))
if
len
(
ellipsedata
)
>
0
:
if
len
(
ellipsedata
)
>
0
:
...
@@ -568,7 +592,7 @@ def write_czml(best_point, all_the_points, ellipsedata, plotallintersects, eps):
...
@@ -568,7 +592,7 @@ def write_czml(best_point, all_the_points, ellipsedata, plotallintersects, eps):
semiMajorAxis
=
x
[
0
]
semiMajorAxis
=
x
[
0
]
semiMinorAxis
=
x
[
1
]
semiMinorAxis
=
x
[
1
]
rotation
=
2
*
np
.
pi
-
x
[
2
]
rotation
=
2
*
np
.
pi
-
x
[
2
]
rotation
+=
np
.
pi
/
2
rotation
+=
np
.
pi
/
2
# print(f"{x[2]} Inverted to: {rotation}")
# print(f"{x[2]} Inverted to: {rotation}")
# print(f"SemiMajor: {semiMajorAxis}, Semiminor: {semiMinorAxis}")
# print(f"SemiMajor: {semiMajorAxis}, Semiminor: {semiMinorAxis}")
# print(f"{x[4], x[3]} is inveted")
# print(f"{x[4], x[3]} is inveted")
...
@@ -580,25 +604,29 @@ def write_czml(best_point, all_the_points, ellipsedata, plotallintersects, eps):
...
@@ -580,25 +604,29 @@ def write_czml(best_point, all_the_points, ellipsedata, plotallintersects, eps):
# print(f"SemiMajor: {semiMajorAxis}, Semiminor: {semiMinorAxis}")
# print(f"SemiMajor: {semiMajorAxis}, Semiminor: {semiMinorAxis}")
# print(f"{x[4], x[3]} is NOT inveted")
# print(f"{x[4], x[3]} is NOT inveted")
ellipse_info
=
{
"semiMajorAxis"
:
semiMajorAxis
,
"semiMinorAxis"
:
semiMinorAxis
,
"rotation"
:
rotation
}
ellipse_info
=
{
"semiMajorAxis"
:
semiMajorAxis
,
"semiMinorAxis"
:
semiMinorAxis
,
"rotation"
:
rotation
}
ellipse_packets
.
append
(
Packet
(
id
=
str
(
x
[
4
])
+
", "
+
str
(
x
[
3
]),
ellipse_packets
.
append
(
Packet
(
id
=
str
(
x
[
4
])
+
", "
+
str
(
x
[
3
]),
ellipse
=
{
**
ellipse_properties
,
**
ellipse_info
},
ellipse
=
{
position
=
{
"cartographicDegrees"
:
[
x
[
3
],
x
[
4
],
0
]}))
**
ellipse_properties
,
**
ellipse_info
},
position
=
{
"cartographicDegrees"
:
[
x
[
3
],
x
[
4
],
0
]}))
return
Document
([
top
]
+
best_point_packets
+
all_point_packets
+
ellipse_packets
)
.
dumps
(
separators
=
(
','
,
':'
))
return
Document
([
top
]
+
best_point_packets
+
all_point_packets
+
ellipse_packets
)
.
dumps
(
separators
=
(
','
,
':'
))
###############################################
###############################################
# Writes receivers.czml used by the WebUI
# Writes receivers.czml used by the WebUI
###############################################
###############################################
@get
(
'/receivers.czml'
)
@get
(
'/receivers.czml'
)
def
write_rx_czml
():
def
write_rx_czml
():
response
.
set_header
(
'Cache-Control'
,
'no-cache, no-store, must-revalidate, max-age=0'
)
response
.
set_header
(
'Cache-Control'
,
'no-cache, no-store, must-revalidate, max-age=0'
)
height
=
50
height
=
50
min_conf
=
ms
.
min_conf
min_conf
=
ms
.
min_conf
min_power
=
ms
.
min_power
min_power
=
ms
.
min_power
green
=
[
0
,
255
,
0
,
255
]
green
=
[
0
,
255
,
0
,
255
]
orange
=
[
255
,
140
,
0
,
255
]
orange
=
[
255
,
140
,
0
,
255
]
red
=
[
255
,
0
,
0
,
255
]
red
=
[
255
,
0
,
0
,
255
]
receiver_point_packets
=
[]
receiver_point_packets
=
[]
lob_packets
=
[]
lob_packets
=
[]
top
=
Preamble
(
name
=
"Receivers"
)
top
=
Preamble
(
name
=
"Receivers"
)
...
@@ -607,7 +635,7 @@ def write_rx_czml():
...
@@ -607,7 +635,7 @@ def write_rx_czml():
"verticalOrigin"
:
"BOTTOM"
,
"verticalOrigin"
:
"BOTTOM"
,
"zIndex"
:
9
,
"zIndex"
:
9
,
"scale"
:
0.75
,
"scale"
:
0.75
,
"heightReference"
:
"CLAMP_TO_GROUND"
,
"heightReference"
:
"CLAMP_TO_GROUND"
,
"height"
:
48
,
"height"
:
48
,
"width"
:
48
,
"width"
:
48
,
}
}
...
@@ -622,42 +650,48 @@ def write_rx_czml():
...
@@ -622,42 +650,48 @@ def write_rx_czml():
lob_color
=
red
lob_color
=
red
lob_start_lat
=
x
.
latitude
lob_start_lat
=
x
.
latitude
lob_start_lon
=
x
.
longitude
lob_start_lon
=
x
.
longitude
lob_stop_lat
,
lob_stop_lon
=
v
.
direct
(
lob_start_lat
,
lob_start_lon
,
x
.
doa
,
x
.
lob_length
())
lob_stop_lat
,
lob_stop_lon
=
v
.
direct
(
lob_start_lat
,
lob_start_lon
,
x
.
doa
,
x
.
lob_length
())
lob_packets
.
append
(
Packet
(
id
=
f
"LOB-{x.station_id}-{index}"
,
lob_packets
.
append
(
Packet
(
id
=
f
"LOB-{x.station_id}-{index}"
,
polyline
=
Polyline
(
polyline
=
Polyline
(
material
=
Material
(
polylineOutline
=
material
=
Material
(
polylineOutline
=
PolylineOutlineMaterial
(
PolylineOutlineMaterial
(
color
=
Color
(
color
=
Color
(
rgba
=
lob_color
),
rgba
=
lob_color
),
outlineColor
=
Color
(
rgba
=
[
0
,
0
,
0
,
255
]),
outlineColor
=
Color
(
outlineWidth
=
2
rgba
=
[
0
,
0
,
0
,
255
]),
outlineWidth
=
2
)),
)),
clampToGround
=
True
,
clampToGround
=
True
,
width
=
5
,
width
=
5
,
positions
=
Position
(
cartographicDegrees
=
[
lob_start_lon
,
lob_start_lat
,
height
,
lob_stop_lon
,
lob_stop_lat
,
height
])
positions
=
Position
(
cartographicDegrees
=
[
lob_start_lon
,
lob_start_lat
,
height
,
lob_stop_lon
,
lob_stop_lat
,
height
])
)))
)))
else
:
else
:
lob_packets
=
[]
lob_packets
=
[]
if
x
.
isMobile
==
True
:
if
x
.
isMobile
is
True
:
rx_icon
=
{
"image"
:
{
"uri"
:
"/static/flipped_car.svg"
}}
rx_icon
=
{
"image"
:
{
"uri"
:
"/static/flipped_car.svg"
}}
# if x.heading > 0 or x.heading < 180:
# if x.heading > 0 or x.heading < 180:
# rx_icon = {"image":{"uri":"/static/flipped_car.svg"}, "rotation":math.radians(360 - x.heading + 90)}
# rx_icon = {"image":{"uri":"/static/flipped_car.svg"}, "rotation":math.radians(360 - x.heading + 90)}
# elif x.heading < 0 or x.heading > 180:
# elif x.heading < 0 or x.heading > 180:
# rx_icon = {"image":{"uri":"/static/car.svg"}, "rotation":math.radians(360 - x.heading - 90)}
# rx_icon = {"image":{"uri":"/static/car.svg"}, "rotation":math.radians(360 - x.heading - 90)}
else
:
else
:
rx_icon
=
{
"image"
:
{
"uri"
:
"/static/tower.svg"
}}
rx_icon
=
{
"image"
:
{
"uri"
:
"/static/tower.svg"
}}
receiver_point_packets
.
append
(
Packet
(
id
=
f
"{x.station_id}-{index}"
,
receiver_point_packets
.
append
(
Packet
(
id
=
f
"{x.station_id}-{index}"
,
billboard
=
{
**
rx_properties
,
**
rx_icon
},
billboard
=
{
position
=
{
"cartographicDegrees"
:
[
x
.
longitude
,
x
.
latitude
,
15
]}))
**
rx_properties
,
**
rx_icon
},
position
=
{
"cartographicDegrees"
:
[
x
.
longitude
,
x
.
latitude
,
15
]}))
return
Document
([
top
]
+
receiver_point_packets
+
lob_packets
)
.
dumps
(
separators
=
(
','
,
':'
))
return
Document
([
top
]
+
receiver_point_packets
+
lob_packets
)
.
dumps
(
separators
=
(
','
,
':'
))
###############################################
###############################################
# Writes aoi.czml used by the WebUI
# Writes aoi.czml used by the WebUI
###############################################
###############################################
@get
(
"/aoi.czml"
)
@get
(
"/aoi.czml"
)
def
wr_aoi_czml
():
def
wr_aoi_czml
():
response
.
set_header
(
'Cache-Control'
,
'no-cache, no-store, must-revalidate, max-age=0'
)
response
.
set_header
(
'Cache-Control'
,
'no-cache, no-store, must-revalidate, max-age=0'
)
aoi_packets
=
[]
aoi_packets
=
[]
top
=
Preamble
(
name
=
"AOIs"
)
top
=
Preamble
(
name
=
"AOIs"
)
area_of_interest_properties
=
{
area_of_interest_properties
=
{
...
@@ -673,7 +707,7 @@ def wr_aoi_czml():
...
@@ -673,7 +707,7 @@ def wr_aoi_czml():
},
},
"outline"
:
True
,
"outline"
:
True
,
"outlineWidth"
:
2
,
"outlineWidth"
:
2
,
"outlineColor"
:
{
"rgba"
:
[
53
,
184
,
240
,
255
],},
"outlineColor"
:
{
"rgba"
:
[
53
,
184
,
240
,
255
],
},
},
},
exclusion_area_properties
=
{
exclusion_area_properties
=
{
...
@@ -689,7 +723,7 @@ def wr_aoi_czml():
...
@@ -689,7 +723,7 @@ def wr_aoi_czml():
},
},
"outline"
:
True
,
"outline"
:
True
,
"outlineWidth"
:
2
,
"outlineWidth"
:
2
,
"outlineColor"
:
{
"rgba"
:
[
224
,
142
,
0
,
255
],},
"outlineColor"
:
{
"rgba"
:
[
224
,
142
,
0
,
255
],
},
},
},
for
x
in
fetch_aoi_data
():
for
x
in
fetch_aoi_data
():
...
@@ -704,15 +738,17 @@ def wr_aoi_czml():
...
@@ -704,15 +738,17 @@ def wr_aoi_czml():
aoi_properties
=
area_of_interest_properties
[
0
]
aoi_properties
=
area_of_interest_properties
[
0
]
elif
aoi
[
'aoi_type'
]
==
"exclusion"
:
elif
aoi
[
'aoi_type'
]
==
"exclusion"
:
aoi_properties
=
exclusion_area_properties
[
0
]
aoi_properties
=
exclusion_area_properties
[
0
]
aoi_info
=
{
"semiMajorAxis"
:
aoi
[
'radius'
],
"semiMinorAxis"
:
aoi
[
'radius'
],
"rotation"
:
0
}
aoi_info
=
{
"semiMajorAxis"
:
aoi
[
'radius'
],
"semiMinorAxis"
:
aoi
[
'radius'
],
"rotation"
:
0
}
aoi_packets
.
append
(
Packet
(
id
=
aoi
[
'aoi_type'
]
+
str
(
aoi
[
'uid'
]),
aoi_packets
.
append
(
Packet
(
id
=
aoi
[
'aoi_type'
]
+
str
(
aoi
[
'uid'
]),
ellipse
=
{
**
aoi_properties
,
**
aoi_info
},
ellipse
=
{
**
aoi_properties
,
**
aoi_info
},
position
=
{
"cartographicDegrees"
:
[
aoi
[
'longitude'
],
aoi
[
'latitude'
],
0
]}))
position
=
{
"cartographicDegrees"
:
[
aoi
[
'longitude'
],
aoi
[
'latitude'
],
0
]}))
return
Document
([
top
]
+
aoi_packets
)
.
dumps
(
separators
=
(
','
,
':'
))
return
Document
([
top
]
+
aoi_packets
)
.
dumps
(
separators
=
(
','
,
':'
))
###############################################
###############################################
# C
L
ears the screen if debugging is off.
# C
l
ears the screen if debugging is off.
###############################################
###############################################
def
clear
(
debugging
):
def
clear
(
debugging
):
if
not
debugging
:
if
not
debugging
:
...
@@ -723,6 +759,7 @@ def clear(debugging):
...
@@ -723,6 +759,7 @@ def clear(debugging):
else
:
else
:
_
=
system
(
'clear'
)
_
=
system
(
'clear'
)
###############################################
###############################################
# Serves static files such as CSS and JS to the
# Serves static files such as CSS and JS to the
# WebUI
# WebUI
...
@@ -730,9 +767,11 @@ def clear(debugging):
...
@@ -730,9 +767,11 @@ def clear(debugging):
@route
(
'/static/<filepath:path>'
,
name
=
'static'
)
@route
(
'/static/<filepath:path>'
,
name
=
'static'
)
def
server_static
(
filepath
):
def
server_static
(
filepath
):
response
=
static_file
(
filepath
,
root
=
'./static'
)
response
=
static_file
(
filepath
,
root
=
'./static'
)
response
.
set_header
(
'Cache-Control'
,
'no-cache, no-store, must-revalidate, max-age=0'
)
response
.
set_header
(
'Cache-Control'
,
'no-cache, no-store, must-revalidate, max-age=0'
)
return
response
return
response
###############################################
###############################################
# Loads the main page of the WebUI
# Loads the main page of the WebUI
# http://[ip]:[port]/
# http://[ip]:[port]/
...
@@ -741,16 +780,18 @@ def server_static(filepath):
...
@@ -741,16 +780,18 @@ def server_static(filepath):
@get
(
'/index'
)
@get
(
'/index'
)
@get
(
'/cesium'
)
@get
(
'/cesium'
)
def
cesium
():
def
cesium
():
response
.
set_header
(
'Cache-Control'
,
'no-cache, no-store, must-revalidate, max-age=0'
)
response
.
set_header
(
'Cache-Control'
,
'no-cache, no-store, must-revalidate, max-age=0'
)
return
template
(
'cesium.tpl'
,
return
template
(
'cesium.tpl'
,
{
'access_token'
:
access_token
,
{
'access_token'
:
access_token
,
'epsilon'
:
ms
.
eps
,
'epsilon'
:
ms
.
eps
,
'minpower'
:
ms
.
min_power
,
'minpower'
:
ms
.
min_power
,
'minconf'
:
ms
.
min_conf
,
'minconf'
:
ms
.
min_conf
,
'minpoints'
:
ms
.
min_samp
,
'minpoints'
:
ms
.
min_samp
,
'rx_state'
:
"checked"
if
ms
.
receiving
==
True
else
""
,
'rx_state'
:
"checked"
if
ms
.
receiving
is
True
else
""
,
'intersect_state'
:
"checked"
if
ms
.
plotintersects
==
True
else
""
,
'intersect_state'
:
"checked"
if
ms
.
plotintersects
is
True
else
""
,
'receivers'
:
receivers
})
'receivers'
:
receivers
})
###############################################
###############################################
# GET Request to update parameters from the
# GET Request to update parameters from the
...
@@ -760,8 +801,10 @@ def cesium():
...
@@ -760,8 +801,10 @@ def cesium():
def
update_cesium
():
def
update_cesium
():
# eps = float(request.query.eps) if request.query.eps else ms.eps
# eps = float(request.query.eps) if request.query.eps else ms.eps
# min_samp = float(request.query.minpts) if request.query.minpts else ms.min_samp
# min_samp = float(request.query.minpts) if request.query.minpts else ms.min_samp
ms
.
min_conf
=
float
(
request
.
query
.
minconf
)
if
request
.
query
.
minconf
else
ms
.
min_conf
ms
.
min_conf
=
float
(
ms
.
min_power
=
float
(
request
.
query
.
minpower
)
if
request
.
query
.
minpower
else
ms
.
min_power
request
.
query
.
minconf
)
if
request
.
query
.
minconf
else
ms
.
min_conf
ms
.
min_power
=
float
(
request
.
query
.
minpower
)
if
request
.
query
.
minpower
else
ms
.
min_power
if
request
.
query
.
rx
==
"true"
:
if
request
.
query
.
rx
==
"true"
:
ms
.
receiving
=
True
ms
.
receiving
=
True
...
@@ -775,6 +818,7 @@ def update_cesium():
...
@@ -775,6 +818,7 @@ def update_cesium():
return
"OK"
return
"OK"
###############################################
###############################################
# Returns a JSON file to the WebUI with
# Returns a JSON file to the WebUI with
# information to fill in the RX cards.
# information to fill in the RX cards.
...
@@ -782,7 +826,7 @@ def update_cesium():
...
@@ -782,7 +826,7 @@ def update_cesium():
@get
(
'/rx_params'
)
@get
(
'/rx_params'
)
def
rx_params
():
def
rx_params
():
all_rx
=
{
'receivers'
:{}}
all_rx
=
{
'receivers'
:
{}}
rx_properties
=
[]
rx_properties
=
[]
for
index
,
x
in
enumerate
(
receivers
):
for
index
,
x
in
enumerate
(
receivers
):
x
.
update
()
x
.
update
()
...
@@ -793,6 +837,7 @@ def rx_params():
...
@@ -793,6 +837,7 @@ def rx_params():
response
.
headers
[
'Content-Type'
]
=
'application/json'
response
.
headers
[
'Content-Type'
]
=
'application/json'
return
json
.
dumps
(
all_rx
)
return
json
.
dumps
(
all_rx
)
###############################################
###############################################
# Returns a CZML file that contains intersect
# Returns a CZML file that contains intersect
# and ellipse information for Cesium.
# and ellipse information for Cesium.
...
@@ -800,17 +845,21 @@ def rx_params():
...
@@ -800,17 +845,21 @@ def rx_params():
@get
(
'/output.czml'
)
@get
(
'/output.czml'
)
def
tx_czml_out
():
def
tx_czml_out
():
eps
=
request
.
query
.
eps
if
request
.
query
.
eps
else
str
(
ms
.
eps
)
eps
=
request
.
query
.
eps
if
request
.
query
.
eps
else
str
(
ms
.
eps
)
min_samp
=
request
.
query
.
minpts
if
request
.
query
.
minpts
else
str
(
ms
.
min_samp
)
min_samp
=
request
.
query
.
minpts
if
request
.
query
.
minpts
else
str
(
ms
.
min_samp
)
if
request
.
query
.
plotpts
==
"true"
:
if
request
.
query
.
plotpts
==
"true"
:
plotallintersects
=
True
plotallintersects
=
True
elif
request
.
query
.
plotpts
==
"false"
:
elif
request
.
query
.
plotpts
==
"false"
:
plotallintersects
=
False
plotallintersects
=
False
else
:
else
:
plotallintersects
=
ms
.
plotintersects
plotallintersects
=
ms
.
plotintersects
response
.
set_header
(
'Cache-Control'
,
'no-cache, no-store, must-revalidate, max-age=0'
)
response
.
set_header
(
output
=
write_czml
(
*
process_data
(
database_name
,
eps
,
min_samp
),
plotallintersects
,
eps
)
'Cache-Control'
,
'no-cache, no-store, must-revalidate, max-age=0'
)
output
=
write_czml
(
*
process_data
(
database_name
,
eps
,
min_samp
),
plotallintersects
,
eps
)
return
str
(
output
)
return
str
(
output
)
###############################################
###############################################
# PUT request to update receiver variables
# PUT request to update receiver variables
# from the WebUI
# from the WebUI
...
@@ -824,7 +873,8 @@ def update_rx(action):
...
@@ -824,7 +873,8 @@ def update_rx(action):
elif
action
==
"del"
:
elif
action
==
"del"
:
index
=
int
(
data
[
'uid'
])
index
=
int
(
data
[
'uid'
])
command
=
"DELETE FROM receivers WHERE station_id=?"
command
=
"DELETE FROM receivers WHERE station_id=?"
DATABASE_EDIT_Q
.
put
((
command
,
[(
receivers
[
index
]
.
station_id
,),],
True
))
DATABASE_EDIT_Q
.
put
(
(
command
,
[(
receivers
[
index
]
.
station_id
,),
],
True
))
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
# del_receiver(receivers[index].station_id)
# del_receiver(receivers[index].station_id)
...
@@ -845,13 +895,14 @@ def update_rx(action):
...
@@ -845,13 +895,14 @@ def update_rx(action):
print
(
"I got some bad data. Doing nothing out of spite."
)
print
(
"I got some bad data. Doing nothing out of spite."
)
return
redirect
(
'/rx_params'
)
return
redirect
(
'/rx_params'
)
###############################################
###############################################
# Returns a JSON file to the WebUI with
# Returns a JSON file to the WebUI with
# information to fill in the AOI cards.
# information to fill in the AOI cards.
###############################################
###############################################
@get
(
'/interest_areas'
)
@get
(
'/interest_areas'
)
def
load_interest_areas
():
def
load_interest_areas
():
all_aoi
=
{
'aois'
:{}}
all_aoi
=
{
'aois'
:
{}}
aoi_properties
=
[]
aoi_properties
=
[]
for
x
in
fetch_aoi_data
():
for
x
in
fetch_aoi_data
():
aoi
=
{
aoi
=
{
...
@@ -866,6 +917,7 @@ def load_interest_areas():
...
@@ -866,6 +917,7 @@ def load_interest_areas():
response
.
headers
[
'Content-Type'
]
=
'application/json'
response
.
headers
[
'Content-Type'
]
=
'application/json'
return
json
.
dumps
(
all_aoi
)
return
json
.
dumps
(
all_aoi
)
##########################################
##########################################
# PUT request to add new AOI to DB
# PUT request to add new AOI to DB
##########################################
##########################################
...
@@ -880,33 +932,37 @@ def handle_interest_areas(action):
...
@@ -880,33 +932,37 @@ def handle_interest_areas(action):
add_aoi
(
aoi_type
,
lat
,
lon
,
radius
)
add_aoi
(
aoi_type
,
lat
,
lon
,
radius
)
elif
action
==
"del"
:
elif
action
==
"del"
:
command
=
"UPDATE intersects SET aoi_id=? WHERE aoi_id=?"
command
=
"UPDATE intersects SET aoi_id=? WHERE aoi_id=?"
DATABASE_EDIT_Q
.
put
((
command
,
[(
-
1
,
data
[
'uid'
]),],
True
))
DATABASE_EDIT_Q
.
put
((
command
,
[(
-
1
,
data
[
'uid'
]),
],
True
))
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_RETURN
.
get
(
timeout
=
1
)
to_table
=
(
str
(
data
[
'uid'
]),)
to_table
=
(
str
(
data
[
'uid'
]),)
command
=
"DELETE FROM interest_areas WHERE uid=?"
command
=
"DELETE FROM interest_areas WHERE uid=?"
DATABASE_EDIT_Q
.
put
((
command
,
[
to_table
,],
True
))
DATABASE_EDIT_Q
.
put
((
command
,
[
to_table
,
],
True
))
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
elif
action
==
"purge"
:
elif
action
==
"purge"
:
conn
=
sqlite3
.
connect
(
database_name
)
conn
=
sqlite3
.
connect
(
database_name
)
c
=
conn
.
cursor
()
c
=
conn
.
cursor
()
c
.
execute
(
"SELECT aoi_type, latitude, longitude, radius FROM interest_areas WHERE uid=?"
,
[
data
[
'uid'
]])
c
.
execute
(
"SELECT aoi_type, latitude, longitude, radius FROM interest_areas WHERE uid=?"
,
[
data
[
'uid'
]])
properties
=
c
.
fetchone
()
properties
=
c
.
fetchone
()
conn
.
close
()
conn
.
close
()
purge_database
(
*
properties
)
purge_database
(
*
properties
)
###############################################
###############################################
# Starts the Bottle webserver.
# Starts the Bottle webserver.
###############################################
###############################################
def
start_server
(
ipaddr
=
"127.0.0.1"
,
port
=
8080
):
def
start_server
(
ipaddr
=
"127.0.0.1"
,
port
=
8080
):
try
:
try
:
run
(
host
=
ipaddr
,
port
=
port
,
quiet
=
True
,
server
=
GeventWebSocketServer
,
debug
=
True
)
run
(
host
=
ipaddr
,
port
=
port
,
quiet
=
True
,
server
=
GeventWebSocketServer
,
debug
=
True
)
except
OSError
:
except
OSError
:
print
(
f
"Port {port} seems to be in use. Please select another port or "
+
print
(
f
"Port {port} seems to be in use. Please select another port or "
+
"check if another instance of DFA is already running."
)
"check if another instance of DFA is already running."
)
debugging
=
True
debugging
=
True
finish
()
finish
()
###############################################
###############################################
# Captures DOA data and computes intersections
# Captures DOA data and computes intersections
# if the receiver is enabled. Writes the
# if the receiver is enabled. Writes the
...
@@ -921,16 +977,17 @@ def run_receiver(receivers):
...
@@ -921,16 +977,17 @@ def run_receiver(receivers):
while
ms
.
receiving
:
while
ms
.
receiving
:
if
not
debugging
:
if
not
debugging
:
print
(
"Receiving"
+
dots
*
'.'
)
print
(
"Receiving"
+
dots
*
'.'
)
print
(
"Press Control+C to process data and exit."
)
print
(
"Press Control+C to process data and exit."
)
# Main loop to compute intersections between multiple receivers
# Main loop to compute intersections between multiple receivers
intersect_list
=
np
.
array
([])
.
reshape
(
0
,
3
)
intersect_list
=
np
.
array
([])
.
reshape
(
0
,
3
)
ms
.
rx_busy
=
True
ms
.
rx_busy
=
True
for
rx
in
receivers
:
for
rx
in
receivers
:
try
:
try
:
if
rx
.
isActive
:
rx
.
update
()
if
rx
.
isActive
:
rx
.
update
()
except
IOError
:
except
IOError
:
print
(
"Problem connecting to receiver."
)
print
(
"Problem connecting to receiver."
)
rx
.
d_2_last_intersection
=
[]
rx
.
d_2_last_intersection
=
[]
...
@@ -953,14 +1010,17 @@ def run_receiver(receivers):
...
@@ -953,14 +1010,17 @@ def run_receiver(receivers):
receivers
[
y
]
.
d_2_last_intersection
.
append
(
v
.
haversine
(
receivers
[
y
]
.
d_2_last_intersection
.
append
(
v
.
haversine
(
receivers
[
y
]
.
latitude
,
receivers
[
y
]
.
longitude
,
*
intersection
))
receivers
[
y
]
.
latitude
,
receivers
[
y
]
.
longitude
,
*
intersection
))
intersection
=
list
(
intersection
)
intersection
=
list
(
intersection
)
avg_conf
=
np
.
mean
([
receivers
[
x
]
.
confidence
,
receivers
[
y
]
.
confidence
])
avg_conf
=
np
.
mean
(
[
receivers
[
x
]
.
confidence
,
receivers
[
y
]
.
confidence
])
intersection
.
append
(
avg_conf
)
intersection
.
append
(
avg_conf
)
intersection
=
np
.
array
([
intersection
])
intersection
=
np
.
array
([
intersection
])
if
intersection
.
any
()
!=
None
:
if
intersection
.
any
()
is
not
None
:
intersect_list
=
np
.
concatenate
((
intersect_list
,
intersection
),
axis
=
0
)
intersect_list
=
np
.
concatenate
(
(
intersect_list
,
intersection
),
axis
=
0
)
if
intersect_list
.
size
!=
0
:
if
intersect_list
.
size
!=
0
:
avg_coord
=
np
.
average
(
intersect_list
[:,
0
:
3
],
weights
=
intersect_list
[:,
2
],
axis
=
0
)
avg_coord
=
np
.
average
(
intersect_list
[:,
0
:
3
],
weights
=
intersect_list
[:,
2
],
axis
=
0
)
keep
,
in_aoi
=
check_aoi
(
*
avg_coord
[
0
:
2
])
keep
,
in_aoi
=
check_aoi
(
*
avg_coord
[
0
:
2
])
if
keep
:
if
keep
:
to_table
=
[
receivers
[
x
]
.
doa_time
,
round
(
avg_coord
[
0
],
6
),
round
(
avg_coord
[
1
],
6
),
to_table
=
[
receivers
[
x
]
.
doa_time
,
round
(
avg_coord
[
0
],
6
),
round
(
avg_coord
[
1
],
6
),
...
@@ -979,7 +1039,7 @@ def run_receiver(receivers):
...
@@ -979,7 +1039,7 @@ def run_receiver(receivers):
rx
.
doa_time
>=
rx
.
previous_doa_time
+
10000
):
rx
.
doa_time
>=
rx
.
previous_doa_time
+
10000
):
current_doa
=
[
rx
.
doa_time
,
rx
.
station_id
,
rx
.
latitude
,
current_doa
=
[
rx
.
doa_time
,
rx
.
station_id
,
rx
.
latitude
,
rx
.
longitude
,
rx
.
confidence
,
rx
.
doa
]
rx
.
longitude
,
rx
.
confidence
,
rx
.
doa
]
min_time
=
rx
.
doa_time
-
1200000
#
15 Minutes
min_time
=
rx
.
doa_time
-
1200000
#
15 Minutes
c
.
execute
(
'''SELECT latitude, longitude, confidence, lob FROM lobs
c
.
execute
(
'''SELECT latitude, longitude, confidence, lob FROM lobs
WHERE station_id = ? AND time > ?'''
,
[
rx
.
station_id
,
min_time
])
WHERE station_id = ? AND time > ?'''
,
[
rx
.
station_id
,
min_time
])
lob_array
=
c
.
fetchall
()
lob_array
=
c
.
fetchall
()
...
@@ -995,7 +1055,8 @@ def run_receiver(receivers):
...
@@ -995,7 +1055,8 @@ def run_receiver(receivers):
lon_rxb
=
previous
[
1
]
lon_rxb
=
previous
[
1
]
conf_rxb
=
previous
[
2
]
conf_rxb
=
previous
[
2
]
doa_rxb
=
previous
[
3
]
doa_rxb
=
previous
[
3
]
spacial_diversity
,
z
=
v
.
inverse
((
lat_rxa
,
lon_rxa
),
(
lat_rxb
,
lon_rxb
))
spacial_diversity
,
z
=
v
.
inverse
(
(
lat_rxa
,
lon_rxa
),
(
lat_rxb
,
lon_rxb
))
min_diversity
=
500
min_diversity
=
500
if
(
spacial_diversity
>
min_diversity
and
if
(
spacial_diversity
>
min_diversity
and
abs
(
doa_rxa
-
doa_rxb
)
>
5
):
abs
(
doa_rxa
-
doa_rxb
)
>
5
):
...
@@ -1013,12 +1074,13 @@ def run_receiver(receivers):
...
@@ -1013,12 +1074,13 @@ def run_receiver(receivers):
command
=
'''INSERT INTO intersects
command
=
'''INSERT INTO intersects
(time, latitude, longitude, num_parents, confidence, aoi_id)
(time, latitude, longitude, num_parents, confidence, aoi_id)
VALUES (?,?,?,?,?,?)'''
VALUES (?,?,?,?,?,?)'''
DATABASE_EDIT_Q
.
put
((
command
,
(
to_table
,),
True
))
DATABASE_EDIT_Q
.
put
(
(
command
,
(
to_table
,),
True
))
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_RETURN
.
get
(
timeout
=
1
)
print
(
f
"Computed and kept {keep_count} intersections."
)
print
(
f
"Computed and kept {keep_count} intersections."
)
command
=
"INSERT INTO lobs VALUES (?,?,?,?,?,?)"
command
=
"INSERT INTO lobs VALUES (?,?,?,?,?,?)"
DATABASE_EDIT_Q
.
put
((
command
,
[
current_doa
,],
True
))
DATABASE_EDIT_Q
.
put
((
command
,
[
current_doa
,
],
True
))
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
...
@@ -1037,6 +1099,7 @@ def run_receiver(receivers):
...
@@ -1037,6 +1099,7 @@ def run_receiver(receivers):
conn
.
close
()
conn
.
close
()
###############################################
###############################################
# Checks if intersection should be kept or not
# Checks if intersection should be kept or not
###############################################
###############################################
...
@@ -1074,6 +1137,7 @@ def check_aoi(lat, lon):
...
@@ -1074,6 +1137,7 @@ def check_aoi(lat, lon):
keep
=
any
(
keep_list
)
keep
=
any
(
keep_list
)
return
keep
,
in_aoi
return
keep
,
in_aoi
###############################################
###############################################
# Adds a new receiver to the program, saves it
# Adds a new receiver to the program, saves it
# in the database.
# in the database.
...
@@ -1088,10 +1152,10 @@ def add_receiver(receiver_url):
...
@@ -1088,10 +1152,10 @@ def add_receiver(receiver_url):
receivers
.
append
(
receiver
(
receiver_url
))
receivers
.
append
(
receiver
(
receiver_url
))
new_rx
=
receivers
[
-
1
]
.
receiver_dict
()
new_rx
=
receivers
[
-
1
]
.
receiver_dict
()
to_table
=
[
new_rx
[
'station_id'
],
new_rx
[
'station_url'
],
new_rx
[
'auto'
],
to_table
=
[
new_rx
[
'station_id'
],
new_rx
[
'station_url'
],
new_rx
[
'auto'
],
new_rx
[
'mobile'
],
new_rx
[
'single'
],
new_rx
[
'latitude'
],
new_rx
[
'longitude'
]]
new_rx
[
'mobile'
],
new_rx
[
'single'
],
new_rx
[
'latitude'
],
new_rx
[
'longitude'
]]
command
=
"INSERT OR IGNORE INTO receivers VALUES (?,?,?,?,?,?,?)"
command
=
"INSERT OR IGNORE INTO receivers VALUES (?,?,?,?,?,?,?)"
DATABASE_EDIT_Q
.
put
((
command
,
[
to_table
,],
True
))
DATABASE_EDIT_Q
.
put
((
command
,
[
to_table
,
],
True
))
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
mobile
=
c
.
execute
(
"SELECT isMobile FROM receivers WHERE station_id = ?"
,
mobile
=
c
.
execute
(
"SELECT isMobile FROM receivers WHERE station_id = ?"
,
...
@@ -1106,6 +1170,7 @@ def add_receiver(receiver_url):
...
@@ -1106,6 +1170,7 @@ def add_receiver(receiver_url):
conn
.
close
()
conn
.
close
()
###############################################
###############################################
# Reads receivers from the database into the
# Reads receivers from the database into the
# program.
# program.
...
@@ -1123,6 +1188,7 @@ def read_rx_table():
...
@@ -1123,6 +1188,7 @@ def read_rx_table():
rx_list
=
[]
rx_list
=
[]
conn
.
close
()
conn
.
close
()
###############################################
###############################################
# Updates the database with any changes made to
# Updates the database with any changes made to
# the receivers.
# the receivers.
...
@@ -1130,7 +1196,8 @@ def read_rx_table():
...
@@ -1130,7 +1196,8 @@ def read_rx_table():
def
update_rx_table
():
def
update_rx_table
():
for
item
in
receivers
:
for
item
in
receivers
:
rx
=
item
.
receiver_dict
()
rx
=
item
.
receiver_dict
()
to_table
=
[
rx
[
'auto'
],
rx
[
'mobile'
],
rx
[
'single'
],
rx
[
'latitude'
],
rx
[
'longitude'
],
rx
[
'station_id'
]]
to_table
=
[
rx
[
'auto'
],
rx
[
'mobile'
],
rx
[
'single'
],
rx
[
'latitude'
],
rx
[
'longitude'
],
rx
[
'station_id'
]]
command
=
'''UPDATE receivers SET
command
=
'''UPDATE receivers SET
isAuto=?,
isAuto=?,
isMobile=?,
isMobile=?,
...
@@ -1138,13 +1205,14 @@ def update_rx_table():
...
@@ -1138,13 +1205,14 @@ def update_rx_table():
latitude=?,
latitude=?,
longitude=?
longitude=?
WHERE station_id = ?'''
WHERE station_id = ?'''
DATABASE_EDIT_Q
.
put
((
command
,
[
to_table
,],
True
))
DATABASE_EDIT_Q
.
put
((
command
,
[
to_table
,
],
True
))
# try:
# try:
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_RETURN
.
get
(
timeout
=
1
)
# except:
# except:
# pass
# pass
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
###############################################
###############################################
# Updates the database with new interest areas.
# Updates the database with new interest areas.
###############################################
###############################################
...
@@ -1154,13 +1222,14 @@ def add_aoi(aoi_type, lat, lon, radius):
...
@@ -1154,13 +1222,14 @@ def add_aoi(aoi_type, lat, lon, radius):
prev_uid
=
c
.
execute
(
'SELECT MAX(uid) from interest_areas'
)
.
fetchone
()[
0
]
prev_uid
=
c
.
execute
(
'SELECT MAX(uid) from interest_areas'
)
.
fetchone
()[
0
]
conn
.
close
()
conn
.
close
()
uid
=
(
prev_uid
+
1
)
if
prev_uid
!=
None
else
0
uid
=
(
prev_uid
+
1
)
if
prev_uid
is
not
None
else
0
to_table
=
[
uid
,
aoi_type
,
lat
,
lon
,
radius
]
to_table
=
[
uid
,
aoi_type
,
lat
,
lon
,
radius
]
command
=
'INSERT INTO interest_areas VALUES (?,?,?,?,?)'
command
=
'INSERT INTO interest_areas VALUES (?,?,?,?,?)'
DATABASE_EDIT_Q
.
put
((
command
,
[
to_table
,],
True
))
DATABASE_EDIT_Q
.
put
((
command
,
[
to_table
,
],
True
))
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
DATABASE_EDIT_Q
.
put
((
"done"
,
None
,
False
))
#########################################
#########################################
# Read all the AOIs from the DB
# Read all the AOIs from the DB
#########################################
#########################################
...
@@ -1172,6 +1241,7 @@ def fetch_aoi_data():
...
@@ -1172,6 +1241,7 @@ def fetch_aoi_data():
conn
.
close
()
conn
.
close
()
return
aoi_list
return
aoi_list
###############################################
###############################################
# One thread responsible for all database write
# One thread responsible for all database write
# operations.
# operations.
...
@@ -1226,6 +1296,7 @@ def database_writer():
...
@@ -1226,6 +1296,7 @@ def database_writer():
if
reply
:
if
reply
:
DATABASE_RETURN
.
put
(
True
)
DATABASE_RETURN
.
put
(
True
)
###############################################
###############################################
# Thangs to do before closing the program.
# Thangs to do before closing the program.
###############################################
###############################################
...
@@ -1236,19 +1307,23 @@ def finish():
...
@@ -1236,19 +1307,23 @@ def finish():
update_rx_table
()
update_rx_table
()
DATABASE_EDIT_Q
.
put
((
"close"
,
None
,
True
))
DATABASE_EDIT_Q
.
put
((
"close"
,
None
,
True
))
DATABASE_RETURN
.
get
(
timeout
=
1
)
DATABASE_RETURN
.
get
(
timeout
=
1
)
if
geofile
!=
None
:
if
geofile
is
not
None
:
write_geojson
(
*
process_data
(
database_name
)[:
2
])
write_geojson
(
*
process_data
(
database_name
)[:
2
])
kill
(
getpid
(),
signal
.
SIGTERM
)
kill
(
getpid
(),
signal
.
SIGTERM
)
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
###############################################
###############################################
# Help info printed when calling the program
# Help info printed when calling the program
###############################################
###############################################
usage
=
"usage:
%
prog -d FILE [options]"
usage
=
"usage:
%
prog -d FILE [options]"
parser
=
OptionParser
(
usage
=
usage
)
parser
=
OptionParser
(
usage
=
usage
)
parser
.
add_option
(
"-d"
,
"--database"
,
dest
=
"database_name"
,
help
=
"REQUIRED Database File"
,
metavar
=
"FILE"
)
parser
.
add_option
(
"-d"
,
"--database"
,
dest
=
"database_name"
,
parser
.
add_option
(
"-r"
,
"--receivers"
,
dest
=
"rx_file"
,
help
=
"List of receiver URLs"
,
metavar
=
"FILE"
)
help
=
"REQUIRED Database File"
,
metavar
=
"FILE"
)
parser
.
add_option
(
"-g"
,
"--geofile"
,
dest
=
"geofile"
,
help
=
"GeoJSON Output File"
,
metavar
=
"FILE"
)
parser
.
add_option
(
"-r"
,
"--receivers"
,
dest
=
"rx_file"
,
help
=
"List of receiver URLs"
,
metavar
=
"FILE"
)
parser
.
add_option
(
"-g"
,
"--geofile"
,
dest
=
"geofile"
,
help
=
"GeoJSON Output File"
,
metavar
=
"FILE"
)
parser
.
add_option
(
"-e"
,
"--epsilon"
,
dest
=
"eps"
,
help
=
"Max Clustering Distance, Default
\"
auto
\"
."
,
parser
.
add_option
(
"-e"
,
"--epsilon"
,
dest
=
"eps"
,
help
=
"Max Clustering Distance, Default
\"
auto
\"
."
,
metavar
=
"NUMBER or
\"
auto
\"
"
,
default
=
"auto"
)
metavar
=
"NUMBER or
\"
auto
\"
"
,
default
=
"auto"
)
parser
.
add_option
(
"-c"
,
"--confidence"
,
dest
=
"conf"
,
help
=
"Minimum confidence value, default 10"
,
parser
.
add_option
(
"-c"
,
"--confidence"
,
dest
=
"conf"
,
help
=
"Minimum confidence value, default 10"
,
...
@@ -1258,10 +1333,11 @@ if __name__ == '__main__':
...
@@ -1258,10 +1333,11 @@ if __name__ == '__main__':
parser
.
add_option
(
"-m"
,
"--min-samples"
,
dest
=
"minsamp"
,
help
=
"Minimum samples per cluster. Default:
\"
auto
\"
"
,
parser
.
add_option
(
"-m"
,
"--min-samples"
,
dest
=
"minsamp"
,
help
=
"Minimum samples per cluster. Default:
\"
auto
\"
"
,
metavar
=
"NUMBER or
\"
auto
\"
"
,
default
=
"auto"
)
metavar
=
"NUMBER or
\"
auto
\"
"
,
default
=
"auto"
)
parser
.
add_option
(
"--plot_intersects"
,
dest
=
"plotintersects"
,
help
=
"""Plots all the intersect points in a cluster.
parser
.
add_option
(
"--plot_intersects"
,
dest
=
"plotintersects"
,
help
=
"""Plots all the intersect points in a cluster.
Only applies when clustering is turned on. This creates larger CZML files."""
,
action
=
"store_true"
)
Only applies when clustering is turned on. This creates larger CZML files."""
,
action
=
"store_true"
)
parser
.
add_option
(
"-o"
,
"--offline"
,
dest
=
"disable"
,
help
=
"Starts program with receiver turned off."
,
parser
.
add_option
(
"-o"
,
"--offline"
,
dest
=
"disable"
,
help
=
"Starts program with receiver turned off."
,
action
=
"store_false"
,
default
=
True
)
action
=
"store_false"
,
default
=
True
)
parser
.
add_option
(
"--access_token"
,
dest
=
"token_file"
,
help
=
"Cesium Access Token File"
,
metavar
=
"FILE"
)
parser
.
add_option
(
"--access_token"
,
dest
=
"token_file"
,
help
=
"Cesium Access Token File"
,
metavar
=
"FILE"
)
parser
.
add_option
(
"--ip"
,
dest
=
"ipaddr"
,
help
=
"IP Address to serve from. Default 127.0.0.1"
,
parser
.
add_option
(
"--ip"
,
dest
=
"ipaddr"
,
help
=
"IP Address to serve from. Default 127.0.0.1"
,
metavar
=
"IP ADDRESS"
,
type
=
"str"
,
default
=
"127.0.0.1"
)
metavar
=
"IP ADDRESS"
,
type
=
"str"
,
default
=
"127.0.0.1"
)
parser
.
add_option
(
"--port"
,
dest
=
"port"
,
help
=
"Port number to serve from. Default 8080"
,
parser
.
add_option
(
"--port"
,
dest
=
"port"
,
help
=
"Port number to serve from. Default 8080"
,
...
@@ -1294,7 +1370,8 @@ if __name__ == '__main__':
...
@@ -1294,7 +1370,8 @@ if __name__ == '__main__':
else
:
else
:
access_token
=
None
access_token
=
None
web
=
threading
.
Thread
(
target
=
start_server
,
args
=
(
options
.
ipaddr
,
options
.
port
))
web
=
threading
.
Thread
(
target
=
start_server
,
args
=
(
options
.
ipaddr
,
options
.
port
))
web
.
daemon
=
True
web
.
daemon
=
True
web
.
start
()
web
.
start
()
...
@@ -1302,7 +1379,6 @@ if __name__ == '__main__':
...
@@ -1302,7 +1379,6 @@ if __name__ == '__main__':
dbwriter
.
daemon
=
True
dbwriter
.
daemon
=
True
dbwriter
.
start
()
dbwriter
.
start
()
try
:
try
:
###############################################
###############################################
# Reds receivers from the database first, then
# Reds receivers from the database first, then
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment