Added departure filter
This commit is contained in:
parent
3fce82e971
commit
ee7bf407b2
|
@ -79,6 +79,15 @@ class API:
|
||||||
d.set_stop(request.forms.get('stop_id'))
|
d.set_stop(request.forms.get('stop_id'))
|
||||||
return {'success': True}
|
return {'success': True}
|
||||||
|
|
||||||
|
@route('/admin/devices/change_filter', method='POST')
|
||||||
|
def admin_devices_change_filter():
|
||||||
|
if main.config["admin"]["secret"] != request.forms.get('secret'):
|
||||||
|
return {'error': "unauthorized"}
|
||||||
|
for i, d in enumerate(main.controller.devices):
|
||||||
|
if str(i) == request.forms.get('index'):
|
||||||
|
d.set_filter(request.forms.get('filter'))
|
||||||
|
return {'success': True}
|
||||||
|
|
||||||
@route('/admin/devices/toggle', method='POST')
|
@route('/admin/devices/toggle', method='POST')
|
||||||
def admin_devices_toggle():
|
def admin_devices_toggle():
|
||||||
if main.config["admin"]["secret"] != request.forms.get('secret'):
|
if main.config["admin"]["secret"] != request.forms.get('secret'):
|
||||||
|
|
|
@ -2,6 +2,38 @@ from math import floor
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dateutil import parser
|
from dateutil import parser
|
||||||
|
|
||||||
|
class Filter:
|
||||||
|
|
||||||
|
storage = dict()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get(name: str):
|
||||||
|
if name in Filter.storage:
|
||||||
|
return Filter.storage[name]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __init__(self, name: str, filters):
|
||||||
|
if "lines" not in filters:
|
||||||
|
filters["lines"] = None
|
||||||
|
if "types" not in filters:
|
||||||
|
filters["types"] = None
|
||||||
|
if "destinations" not in filters:
|
||||||
|
filters["destinations"] = None
|
||||||
|
self.name = name
|
||||||
|
self.lines = filters["lines"]
|
||||||
|
self.types = filters["types"]
|
||||||
|
self.destinations = filters["destinations"]
|
||||||
|
Filter.storage[name] = self
|
||||||
|
|
||||||
|
def filter(self, departures):
|
||||||
|
results = []
|
||||||
|
for d in departures:
|
||||||
|
if not self.types or d.type in self.types:
|
||||||
|
if not self.lines or d.line in self.lines:
|
||||||
|
if not self.destinations or d.last_stop in self.destinations:
|
||||||
|
results.append(d)
|
||||||
|
return results
|
||||||
|
|
||||||
class Departure:
|
class Departure:
|
||||||
|
|
||||||
id_pool = {}
|
id_pool = {}
|
||||||
|
|
|
@ -7,7 +7,7 @@ from base64 import b64encode
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from random import randint, shuffle
|
from random import randint, shuffle
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from departures import Departure
|
from departures import Departure, Filter
|
||||||
|
|
||||||
import urllib3
|
import urllib3
|
||||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||||
|
@ -34,22 +34,23 @@ class LoraController:
|
||||||
data = requests.post(url, verify=False, headers=headers, data=json.dumps(data)).json()
|
data = requests.post(url, verify=False, headers=headers, data=json.dumps(data)).json()
|
||||||
self.token = data["token"]
|
self.token = data["token"]
|
||||||
|
|
||||||
def new(self, id: int, stop_id: str, enabled: bool):
|
def new(self, id: int, stop_id: str, enabled: bool, filter: Filter):
|
||||||
self.devices.append(LoraDevice(self, id, stop_id, enabled))
|
self.devices.append(LoraDevice(self, id, stop_id, enabled, filter))
|
||||||
|
|
||||||
def json(self):
|
def json(self):
|
||||||
resp = []
|
resp = []
|
||||||
for d in self.devices:
|
for d in self.devices:
|
||||||
resp.append({'id': f"{d.id:0>16x}", 'stop_id': d.stop_id, 'enabled': d.enabled})
|
resp.append({'id': f"{d.id:0>16x}", 'stop_id': d.stop_id, 'enabled': d.enabled, 'filter': d.filter.name if d.filter else None})
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
class LoraDevice:
|
class LoraDevice:
|
||||||
|
|
||||||
def __init__(self, controller: LoraController, deveui: int, stop_id: str, enabled: bool):
|
def __init__(self, controller: LoraController, deveui: int, stop_id: str, enabled: bool, filter: Filter):
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.id = deveui
|
self.id = deveui
|
||||||
self.stop_id = stop_id
|
self.stop_id = stop_id
|
||||||
self.enabled = enabled
|
self.enabled = enabled
|
||||||
|
self.filter = filter
|
||||||
self.message_pool = []
|
self.message_pool = []
|
||||||
self.thread = None
|
self.thread = None
|
||||||
self.port = 1
|
self.port = 1
|
||||||
|
@ -59,11 +60,17 @@ class LoraDevice:
|
||||||
self.clear()
|
self.clear()
|
||||||
self.stop_id = stop_id
|
self.stop_id = stop_id
|
||||||
|
|
||||||
|
def set_filter(self, name: str):
|
||||||
|
self.filter = Filter.get(name)
|
||||||
|
|
||||||
def get_updated_departures(self):
|
def get_updated_departures(self):
|
||||||
if not self.enabled:
|
if not self.enabled:
|
||||||
return
|
return
|
||||||
self.send_time()
|
self.send_time()
|
||||||
for d in Departure.get(self.stop_id):
|
departures = Departure.get(self.stop_id)
|
||||||
|
if self.filter:
|
||||||
|
departures = self.filter.filter(departures)
|
||||||
|
for d in departures:
|
||||||
if self.id not in d.updated or d.updated[self.id] > 0:
|
if self.id not in d.updated or d.updated[self.id] > 0:
|
||||||
self.send(d.data)
|
self.send(d.data)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from departures import Departure
|
from departures import Departure, Filter
|
||||||
from requests.structures import CaseInsensitiveDict
|
from requests.structures import CaseInsensitiveDict
|
||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
|
@ -24,11 +24,15 @@ class Main:
|
||||||
self.controller = lora_controller
|
self.controller = lora_controller
|
||||||
self.api = API(self)
|
self.api = API(self)
|
||||||
lora_controller.generate_token()
|
lora_controller.generate_token()
|
||||||
|
for name in self.config["filters"]:
|
||||||
|
Filter(name, self.config["filters"][name])
|
||||||
for d in self.config["devices"]:
|
for d in self.config["devices"]:
|
||||||
if "stop_id" in d:
|
if "stop_id" in d:
|
||||||
if "enabled" not in d:
|
if "enabled" not in d:
|
||||||
d["enabled"] = True
|
d["enabled"] = True
|
||||||
lora_controller.new(d["id"], str(d["stop_id"]), d["enabled"])
|
if "filter" not in d:
|
||||||
|
d["filter"] = None
|
||||||
|
lora_controller.new(d["id"], str(d["stop_id"]), d["enabled"], Filter.get(d["filter"]))
|
||||||
self.thread = threading.Thread(target=self.update_loop)
|
self.thread = threading.Thread(target=self.update_loop)
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,13 @@
|
||||||
|
|
||||||
.cards .header {padding: 15px; display: grid; grid-template-columns: 1fr max-content; user-select: none;}
|
.cards .header {padding: 15px; display: grid; grid-template-columns: 1fr max-content; user-select: none;}
|
||||||
.cards .first {font-weight: 700;}
|
.cards .first {font-weight: 700;}
|
||||||
.cards .settings {padding: 15px; border-top: 1px solid var(--border-color2); background: var(--alt-bg2); display: none;}
|
.cards .settings {padding: 15px; border-top: 1px solid var(--border-color2); background: var(--alt-bg2); display: none; flex-direction: column; gap: 13px;}
|
||||||
.cards .settings.visible {display: block;}
|
.cards .settings.visible {display: flex;}
|
||||||
|
|
||||||
.cards .actions {display: flex; gap: 10px; flex-wrap: wrap; align-items: center;}
|
.cards .actions {display: flex; gap: 10px; flex-wrap: wrap; align-items: center;}
|
||||||
.cards .actions::before {content: "Akce:"; font-weight: 500; font-size: 90%; opacity: .5; text-transform: uppercase;}
|
.cards .actions::before, .cards .filter::before {content: "Akce:"; font-weight: 500; font-size: 90%; opacity: .5; text-transform: uppercase;}
|
||||||
|
.cards .filter::before {content: "Aktivní filtr:"; margin-right: 10px;}
|
||||||
|
|
||||||
@media screen and (max-width: 500px) {
|
@media screen and (max-width: 500px) {
|
||||||
.cards .actions::before {display: none;}
|
.cards .actions::before {display: none;}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,14 @@
|
||||||
<div class="second">{{ stops[d.stop_id] ? stops[d.stop_id].name : "Nenastaveno" }}</div>
|
<div class="second">{{ stops[d.stop_id] ? stops[d.stop_id].name : "Nenastaveno" }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings" :class="{ visible: d.visible }">
|
<div class="settings" :class="{ visible: d.visible }">
|
||||||
|
<div class="filter">{{ d.filter ? d.filter : "žádný" }}</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button @click="device_clear(i)">Vymazat</button>
|
<button @click="device_clear(i)">Vymazat</button>
|
||||||
<button @click="device_resend(i)" v-if="d.enabled">Přeposlat</button>
|
|
||||||
<button @click="device_change_stop(i)">Změnit zastávku</button>
|
|
||||||
<button @click="device_toggle(i, false)" v-if="d.enabled">Deaktivovat</button>
|
<button @click="device_toggle(i, false)" v-if="d.enabled">Deaktivovat</button>
|
||||||
<button @click="device_toggle(i, true)" v-else>Aktivovat</button>
|
<button @click="device_toggle(i, true)" v-else>Aktivovat</button>
|
||||||
|
<button @click="device_resend(i)" v-if="d.enabled">Přeposlat</button>
|
||||||
|
<button @click="device_change_stop(i)">Zastávka</button>
|
||||||
|
<button @click="device_change_filter(i)">Filtr</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,10 +3,8 @@ const { createApp } = Vue;
|
||||||
let app = createApp({
|
let app = createApp({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// logged: false,
|
logged: false,
|
||||||
// secret: "",
|
secret: "",
|
||||||
logged: true,
|
|
||||||
secret: "TajneHeslo",
|
|
||||||
stops: {},
|
stops: {},
|
||||||
devices: []
|
devices: []
|
||||||
}
|
}
|
||||||
|
@ -14,11 +12,11 @@ let app = createApp({
|
||||||
methods: {
|
methods: {
|
||||||
async update() {
|
async update() {
|
||||||
let devices = await api("/admin/devices", {secret: this.secret});
|
let devices = await api("/admin/devices", {secret: this.secret});
|
||||||
let stops = await api("/stops");
|
|
||||||
if(devices.error) {
|
if(devices.error) {
|
||||||
alert("Neplatné heslo!");
|
alert("Neplatné heslo!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let stops = await api("/stops");
|
||||||
this.devices = devices.devices;
|
this.devices = devices.devices;
|
||||||
this.stops = stops.stops;
|
this.stops = stops.stops;
|
||||||
this.logged = true;
|
this.logged = true;
|
||||||
|
@ -38,6 +36,12 @@ let app = createApp({
|
||||||
if(!stop_id || stop_id.trim() == "") return;
|
if(!stop_id || stop_id.trim() == "") return;
|
||||||
this.devices[index].stop_id = stop_id;
|
this.devices[index].stop_id = stop_id;
|
||||||
await api("/admin/devices/change_stop", {index, stop_id, secret: this.secret});
|
await api("/admin/devices/change_stop", {index, stop_id, secret: this.secret});
|
||||||
|
},
|
||||||
|
async device_change_filter(index) {
|
||||||
|
let filter = prompt("Zadejte jméno filtru:");
|
||||||
|
if(!filter || filter.trim() == "") return;
|
||||||
|
this.devices[index].filter = filter;
|
||||||
|
await api("/admin/devices/change_filter", {index, filter, secret: this.secret});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).mount('#app');
|
}).mount('#app');
|
||||||
|
@ -63,5 +67,4 @@ async function api(url, data) {
|
||||||
}
|
}
|
||||||
xhr.send(str.join("&"));
|
xhr.send(str.join("&"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
app.update();
|
|
Loading…
Reference in a new issue