Improved backend & multi stop support

This commit is contained in:
Filip Znachor 2022-12-08 22:17:26 +01:00
parent 883bb30fea
commit 6214b6cdf1
5 changed files with 43 additions and 38 deletions

View file

@ -1,5 +1,4 @@
import threading
from operator import itemgetter
from wsgiref.simple_server import make_server, WSGIRequestHandler
from departures import Departure
from bottle import route, error, run, get, ServerAdapter, static_file
@ -17,13 +16,9 @@ class Server(ServerAdapter):
def stop(self):
self.server.shutdown()
@route('/departures')
def index():
resp = []
for d in Departure.storage:
resp.append(Departure.storage[d].json())
resp.sort(key=itemgetter("departure"))
return {'departures': resp}
@route('/departures/<stop_id>')
def index(stop_id: int):
return {'departures': Departure.get(stop_id)}
@get("/")
def static():

View file

@ -1,4 +1,5 @@
from math import floor
from operator import itemgetter
from datetime import datetime
from dateutil import parser
@ -7,6 +8,16 @@ class Departure:
id_pool = []
storage = dict()
@staticmethod
def get(stop_id: str):
resp = []
for id in Departure.storage:
d = Departure.storage[id]
if d.stop_id == int(stop_id):
resp.append(d.json())
resp.sort(key=itemgetter("departure"))
return resp
@staticmethod
def get_id():
i = 0
@ -21,20 +32,20 @@ class Departure:
remove = []
for did in Departure.storage:
d = Departure.storage[did]
if d.get_departure() < -35:
if d.get_departure() < -3.5:
Departure.id_pool.remove(d.id)
remove.append(did)
for did in remove:
Departure.storage.pop(did)
def __init__(self, did, type, line, last_stop, departure, delay, lora_controller):
def __init__(self, did, stop_id, type, line, last_stop, departure, delay, lora_controller):
departure = (parser.parse(departure)).timestamp()
if -(datetime.now().timestamp() - (departure + delay*60))/60 <= -1:
return
Departure.storage[did] = self
if len(last_stop) >= 21:
last_stop = last_stop[:20].strip() + "..."
self.did = did
self.stop_id = stop_id
self.id = Departure.get_id()
self.line = line
self.type = type
@ -43,6 +54,7 @@ class Departure:
self.delay = delay
self.controller = lora_controller
self.controller.data(self)
Departure.storage[did] = self
def update(self, delay):
if delay != self.delay:
@ -50,14 +62,10 @@ class Departure:
self.delay = delay
def get_departure(self):
departure = floor(self.get_accurate_departure()*10)
return departure
def get_accurate_departure(self):
return -((datetime.now().timestamp() - (self.departure + self.delay*60))/60)
return -(floor(((datetime.now().timestamp() - (self.departure + self.delay*60))/60)*10)/10)
def __repr__(self):
return f"{self.id}|{self.type}|{self.line}|{self.last_stop}|{self.get_departure()}"
return f"{self.id}|{self.type}|{self.line}|{self.last_stop}|{(self.get_departure()*10):.0f}"
def json(self):
return {
@ -65,6 +73,6 @@ class Departure:
'line': self.line,
'type': self.type,
'last_stop': self.last_stop,
'departure': floor(self.get_accurate_departure()),
'departure': self.get_departure(),
'delay': self.delay
}

View file

@ -35,8 +35,8 @@ class LoraController:
data = requests.post(url, verify=False, headers=headers, data=json.dumps(data)).json()
self.token = data["token"]
def new(self, id):
self.devices.append(LoraDevice(self, id))
def new(self, id: int, stop_id: int):
self.devices.append(LoraDevice(self, id, stop_id))
def time(self):
def to_string():
@ -46,10 +46,11 @@ class LoraController:
def data(self, data):
for d in self.devices:
d.send(data.__repr__)
if d.stop_id == data.stop_id:
d.send(data.__repr__)
def send(self, id, port, msg):
self.message_pool.append((id, port, msg))
def send(self, id, msg):
self.message_pool.append((id, msg))
if not self.thread or not self.thread.is_alive():
self.thread = threading.Thread(target=self.thread_sending)
self.thread.start()
@ -60,14 +61,14 @@ class LoraController:
break
data = self.message_pool.pop(0)
url = f"https://lora.plzen.eu/api/v2/nodes/{data[0]:0>16x}/queue"
string = data[2]()
string = data[1]()
headers = CaseInsensitiveDict()
headers["Content-Type"] = "application/json"
headers["Authorization"] = f"Bearer {self.token}"
payload = {
"confirmed": True,
"data": b64encode(string.encode("utf-8")).decode("ascii"),
"fPort": data[1],
"fPort": 10,
"reference": "string"
}
requests.post(url, verify=False, headers=headers, data=json.dumps(payload))
@ -75,11 +76,10 @@ class LoraController:
class LoraDevice:
def __init__(self, controller: LoraController, deveui: int):
def __init__(self, controller: LoraController, deveui: int, stop_id: int):
self.controller = controller
self.id = deveui
self.port = 0
self.stop_id = stop_id
def send(self, msg):
self.controller.send(self.id, self.port+1, msg)
self.port = (self.port + 1) % 15
self.controller.send(self.id, msg)

View file

@ -12,7 +12,7 @@ import sys
class Main:
def __init__(self, stop_id):
def __init__(self):
config = Path("config.yml")
try:
self.config = yaml.safe_load(config.read_text(encoding="utf-8-sig"))
@ -20,9 +20,9 @@ class Main:
print("Invalid config file!")
sys.exit(-1)
self.ended = False
self.stop_id = stop_id
lora_controller = LoraController(self)
lora_controller.new(0xbdea85badeedf1)
for d in self.config["devices"]:
lora_controller.new(d["id"], d["stop_id"])
self.controller = lora_controller
self.thread = threading.Thread(target=self.update_loop)
self.thread.start()
@ -44,13 +44,14 @@ class Main:
"FullResults": False
}
resp = requests.post(url, headers=headers, data=json.dumps(data), timeout=100).json()
resp = requests.post(url, headers=headers, data=json.dumps(data), timeout=1000).json()
for c in resp:
did = f"{stop_id}|{abs(c['ConnectionId']['ConnectionId'])}"
if did not in Departure.storage:
Departure(
did,
stop_id,
c["Line"]["TractionType"],
c["Line"]["Name"],
c["LastStopName"],
@ -76,7 +77,8 @@ class Main:
if refetch == 0:
self.controller.time()
self.fetch(self.stop_id, 20)
for s in self.config["stops"]:
self.fetch(s["id"], 15)
refetch = (refetch + 1) % 3
regenerate = (regenerate + 1) % (6*30)
@ -119,5 +121,5 @@ class Main:
except KeyboardInterrupt:
self.stop()
main = Main("40")
main = Main()
main.input_loop()

View file

@ -47,11 +47,11 @@
<div class="header">zpoždění</div>
<div class="header">odjezd</div>
<template v-for="d in departures">
<template v-if="d.departure >= 0">
<template v-if="d.departure > -0.7">
<div class="line" :class="'type'+d.type">{{ d.line }}</div>
<div class="last-stop">{{ d.last_stop }}</div>
<div class="delay">{{ d.delay == 0 ? '' : '+'+d.delay }}</div>
<div class="departure">{{ d.departure == 0 ? '<1' : d.departure }}</div>
<div class="departure">{{ d.departure < 1 ? '<1' : Math.floor(d.departure) }}</div>
</template>
</template>
</div>
@ -78,7 +78,7 @@
resolve(null);
}
};
xhr.open("GET", "/departures", true);
xhr.open("GET", "/departures/40", true);
xhr.send();
});
}