Compare commits
2 Commits
41d60e5019
...
a72472bd16
Author | SHA1 | Date | |
---|---|---|---|
a72472bd16 | |||
93c1596ba8 |
40
testserver.py
Normal file
40
testserver.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import argparse
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
from aiohttp import web
|
||||||
|
|
||||||
|
file = open(pathlib.Path(__file__).parent.absolute() / 'webserver.html', 'r')
|
||||||
|
contecnt = file.read()
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_index(request):
|
||||||
|
return web.Response(content_type='text/html', text=contecnt)
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_ws(request):
|
||||||
|
ws = web.WebSocketResponse()
|
||||||
|
await ws.prepare(request)
|
||||||
|
request.app.ws_clients.append(ws)
|
||||||
|
async for _ in ws: # noqa: WPS328
|
||||||
|
pass
|
||||||
|
request.app.ws_clients.remove(ws)
|
||||||
|
return ws
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--bluetooth-mac', type=str, required=False, help='bluetooth MAC address of radiascan device')
|
||||||
|
parser.add_argument('--listen-host', type=str, required=False, default='0.0.0.0', help='listen host for webserver')
|
||||||
|
parser.add_argument('--listen-port', type=int, required=False, default=8080, help='listen port for webserver')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
app = web.Application()
|
||||||
|
|
||||||
|
|
||||||
|
app.ws_clients = []
|
||||||
|
|
||||||
|
app.add_routes(
|
||||||
|
[
|
||||||
|
web.get('/', handle_index)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
web.run_app(app, host=args.listen_host, port=args.listen_port)
|
181
webserver.html
181
webserver.html
@ -1,21 +1,39 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
|
<!-- Google tag (gtag.js) -->
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-GBWL3K2WMQ"></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag() { dataLayer.push(arguments); }
|
||||||
|
gtag('js', new Date());
|
||||||
|
|
||||||
|
gtag('config', 'G-GBWL3K2WMQ');
|
||||||
|
</script>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Kyiv Radioactive!</title>
|
<title>Київ неРадіоактивний! Проект dead.guru</title>
|
||||||
|
<meta name="description" content="неРадіоактивна ситуація в Києві в реальному часі. Спектр, події, радіаційний фон.">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
|
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/vue-apexcharts"></script>
|
<script src="https://cdn.jsdelivr.net/npm/vue-apexcharts"></script>
|
||||||
|
<link rel="shortcut icon" href="https://kmr.gov.ua/sites/default/files/favicon-kyiv.ico"
|
||||||
|
type="image/vnd.microsoft.icon" />
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
||||||
|
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" />
|
||||||
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
||||||
|
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
|
||||||
|
<script defer src="https://use.fontawesome.com/releases/v5.15.4/js/all.js"
|
||||||
|
integrity="sha384-rOA1PnstxnOBLzCLMcre8ybwbTmemjzdNlILg8O7z1lUkLXozs4DHonlDtnE7fpc"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
<style>
|
<style>
|
||||||
#app>div {
|
#app>div {
|
||||||
margin: 5px auto;
|
margin: 5px auto;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
text-align: center;
|
|
||||||
padding: 5px;
|
|
||||||
border: 1px #aaa dashed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#app fieldset {
|
#app fieldset {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border: 0;
|
border: 0;
|
||||||
@ -26,60 +44,154 @@
|
|||||||
#app>.notification {
|
#app>.notification {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#map {
|
||||||
|
height: 180px;
|
||||||
|
width: 80%;
|
||||||
|
margin: 5px auto;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<section class="section">
|
<section class="section">
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="title">
|
<nav class="navbar is-transparent">
|
||||||
неРадіоактивна ситуація в Києві.
|
<div class="navbar-brand">
|
||||||
</h1>
|
<a class="navbar-item" href="https://kyiv.dead.guru">
|
||||||
<h2 class="subtitle">В реальному часі.</h2>
|
<img src="https://assada.dead.guru/storage/images/logo.png" alt="Bulma: a modern CSS framework based on Flexbox" width="112" height="28">
|
||||||
<div class="notification is-warning">
|
<div><span style="opacity: .9; color: #17914a; font-size: x-small;">не</span><span
|
||||||
Використовуйте ландшавтну орієнтацію екрану для зручного перегляду. Або планшет чи компьютер.
|
style="font-size: x-small;">Радіоактивний!</span></div>
|
||||||
|
|
||||||
|
</a>
|
||||||
|
<div class="navbar-burger" data-target="navbarExampleTransparentExample">
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="navbarExampleTransparentExample" class="navbar-menu">
|
||||||
|
<div class="navbar-start">
|
||||||
|
<a class="navbar-item" href="https://www.saveecobot.com/radiation-maps">
|
||||||
|
Мапа датчиків
|
||||||
|
</a>
|
||||||
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
|
<a class="navbar-link" href="#nav">
|
||||||
|
Корисні посилання
|
||||||
|
</a>
|
||||||
|
<div class="navbar-dropdown is-boxed">
|
||||||
|
<a class="navbar-item" href="https://www.windy.com/?50.321,30.504,9">
|
||||||
|
Мапа вітрів
|
||||||
|
</a>
|
||||||
|
<a class="navbar-item" href="https://bit.ly/3efbPmc">
|
||||||
|
Мапа укриттів
|
||||||
|
</a>
|
||||||
|
</a>
|
||||||
|
<a class="navbar-item" href="https://alerts.in.ua/">
|
||||||
|
Мапа тривог
|
||||||
|
</a>
|
||||||
|
<a class="navbar-item" href="https://bit.ly/3egOosD">
|
||||||
|
Поради від РНБО
|
||||||
|
</a>
|
||||||
|
<a class="navbar-item"
|
||||||
|
href="https://dmbk.kyivcity.gov.ua/content/dii-u-vypadku-zagrozy-vynyknennya-avarii-z-vykydom-rozlyvom-radioaktyvnyh-rechovyn.html">
|
||||||
|
Поради від департаменту муніципальної безпеки
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="navbar-end">
|
||||||
|
<div class="navbar-item">
|
||||||
|
<div class="field is-grouped">
|
||||||
|
<p class="control">
|
||||||
|
<a class="bd-tw-button button" data-social-network="Twitter" data-social-action="tweet"
|
||||||
|
data-social-target="https://bulma.io" target="_blank"
|
||||||
|
href="https://twitter.com/intent/tweet?text=Київ неРадіоактивний! Перевірити можна на &hashtags=КиївНеРадіоактивний&url=https://kyiv.dead.guru">
|
||||||
|
<span class="icon">
|
||||||
|
<i class="fab fa-twitter"></i>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
Tweet
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<div>
|
<div v-if="al" class="notification is-warning">
|
||||||
|
<button class="delete" @click="al = !al"></button>
|
||||||
|
Використовуйте ландшафтну орієнтацію екрану для зручного перегляду. Ще краще — планшет чи комп'ютер.
|
||||||
|
</div>
|
||||||
|
<div style="text-align: center;">
|
||||||
<apexchart type="line" height="350" :options="ratesChartOptions" :series="rates_series"></apexchart>
|
<apexchart type="line" height="350" :options="ratesChartOptions" :series="rates_series"></apexchart>
|
||||||
<button @click="rates_autoupdate = !rates_autoupdate" class="button">Автооновлення: {{ rates_autoupdate ? "ВКЛ" : "ВИКЛ" }}</button>
|
<button @click="rates_autoupdate = !rates_autoupdate" class="button">Автооновлення: {{ rates_autoupdate ?
|
||||||
|
"ВКЛ" : "ВИКЛ" }}</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="notification">
|
<div class="notification">
|
||||||
<strong>До 0,3 мк3в/г - нормальний радіаційний фон.</strong>
|
<strong>До 0,3 мк3в/г — нормальний радіаційний фон.</strong>
|
||||||
<p>
|
<p>
|
||||||
Швидкість дози в мікрозівертах на годину вказує, скільки мікрозівертів (одиниця виміру еквівалентної дози) радіації поглинається організмом або матеріалом за одну годину. Ця величина може використовуватися для оцінки рівня радіаційного впливу на людей, а також для моніторингу і контролю радіаційної безпеки в радіаційних зонах, ядерних установках або природному середовищі.
|
Швидкість дози в мікрозівертах на годину вказує, скільки мікрозівертів (одиниця виміру еквівалентної дози)
|
||||||
|
радіації поглинається організмом або матеріалом за одну годину. Ця величина може використовуватися для
|
||||||
|
оцінки рівня радіаційного впливу на людей, а також для моніторингу і контролю радіаційної безпеки в
|
||||||
|
радіаційних зонах, ядерних установках або природному середовищі.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Наприклад, якщо швидкість дози становить 10 μSv/h, це означає, що організм або матеріал отримує дозу 10 мікрозівертів радіації за кожну годину. Це може вказувати на наявність джерела радіації в цьому місці або на необхідність заходів з радіаційного захисту.
|
Наприклад, якщо швидкість дози становить 10 μSv/h, це означає, що організм або матеріал отримує дозу 10
|
||||||
|
мікрозівертів радіації за кожну годину. Це може вказувати на наявність джерела радіації в цьому місці або на
|
||||||
|
необхідність заходів з радіаційного захисту.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div style="text-align: center;">
|
||||||
<apexchart type="bar" height="350" :options="spectrumChartOptions" :series="spectrum_series"></apexchart>
|
<apexchart type="bar" height="350" :options="spectrumChartOptions" :series="spectrum_series"></apexchart>
|
||||||
<div>
|
<div>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
|
||||||
<label class="checkbox" for="spectrum_x_accum"><input type="checkbox" id="spectrum_x_accum" v-model="spectrum_accum"> Акумульований</label>
|
<label class="checkbox" for="spectrum_x_accum"><input type="checkbox" id="spectrum_x_accum"
|
||||||
|
v-model="spectrum_accum"> Акумульований</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="control">
|
<fieldset class="control">
|
||||||
|
|
||||||
<label class="radio" for="spectrum_x_channel"><input type="radio" id="spectrum_x_channel" v-bind:value="false" v-model="spectrum_energy"> Канал</label>
|
<label class="radio" for="spectrum_x_channel"><input type="radio" id="spectrum_x_channel"
|
||||||
|
v-bind:value="false" v-model="spectrum_energy"> Канал</label>
|
||||||
|
|
||||||
|
|
||||||
<label class="radio" for="spectrum_x_energy"><input type="radio" id="spectrum_x_energy" v-bind:value="true" v-model="spectrum_energy"> Енергія</label>
|
<label class="radio" for="spectrum_x_energy"><input type="radio" id="spectrum_x_energy"
|
||||||
|
v-bind:value="true" v-model="spectrum_energy"> Енергія</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="control">
|
<fieldset class="control">
|
||||||
|
|
||||||
<label class="radio" for="spectrum_linear"><input type="radio" id="spectrum_linear" v-bind:value="false" v-model="spectrum_logarithmic"> Лінійне</label>
|
<label class="radio" for="spectrum_linear"><input type="radio" id="spectrum_linear" v-bind:value="false"
|
||||||
|
v-model="spectrum_logarithmic"> Лінійне</label>
|
||||||
|
|
||||||
<label class="radio" for="spectrum_log"><input type="radio" id="spectrum_log" v-bind:value="true" v-model="spectrum_logarithmic"> Логарифмічне</label>
|
<label class="radio" for="spectrum_log"><input type="radio" id="spectrum_log" v-bind:value="true"
|
||||||
|
v-model="spectrum_logarithmic"> Логарифмічне</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
<button @click="updateSpectrum" class="button">Оновити спектр</button>
|
<button @click="updateSpectrum" class="button">Оновити спектр</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="subtitle">(Частина проекту <a href="https://dead.guru/">dead.guru</a>)</h2>
|
<div id="map"></div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="content has-text-centered">
|
||||||
|
<p>Важливо зазначити що явище радіоактивності не можна застосувати(вживати в контексті) до міста. Прочитати більше можна на <a href="https://uk.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B4%D1%96%D0%BE%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D1%96%D1%81%D1%82%D1%8C">Вікі</a>!</p>
|
||||||
|
<p>
|
||||||
|
Частина проекту <a href="https://dead.guru/"><strong>dead.guru</strong></a>. Код ліцензований
|
||||||
|
<a href="http://opensource.org/licenses/mit-license.php">MIT</a>. Вміст сайту
|
||||||
|
має ліцензію <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY NC SA 4.0</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
<script>
|
<script>
|
||||||
const common_options = {
|
const common_options = {
|
||||||
chart: {
|
chart: {
|
||||||
@ -100,6 +212,7 @@
|
|||||||
ws: null,
|
ws: null,
|
||||||
spectrum_duration: 0,
|
spectrum_duration: 0,
|
||||||
rates_autoupdate: true,
|
rates_autoupdate: true,
|
||||||
|
al: true,
|
||||||
rates_series: [],
|
rates_series: [],
|
||||||
spectrum_accum: false,
|
spectrum_accum: false,
|
||||||
spectrum_series: [],
|
spectrum_series: [],
|
||||||
@ -120,6 +233,9 @@
|
|||||||
watch: {
|
watch: {
|
||||||
spectrum_accum() {
|
spectrum_accum() {
|
||||||
this.updateSpectrum();
|
this.updateSpectrum();
|
||||||
|
},
|
||||||
|
al(newAl) {
|
||||||
|
localStorage.al = newAl === true ? "ok!" : "no";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -140,10 +256,30 @@
|
|||||||
this.ws = new WebSocket('wss://' + window.location.host + '/ws')
|
this.ws = new WebSocket('wss://' + window.location.host + '/ws')
|
||||||
this.ws.onmessage = this.onmessage;
|
this.ws.onmessage = this.onmessage;
|
||||||
this.updateSpectrum();
|
this.updateSpectrum();
|
||||||
|
var map = L.map('map').setView([50.51847778550632, 30.508852993206236], 10);
|
||||||
|
|
||||||
|
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
maxZoom: 10,
|
||||||
|
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||||
|
}).addTo(map);
|
||||||
|
var circle = L.circle([50.51847778550632, 30.508852993206236], {
|
||||||
|
color: '#164299',
|
||||||
|
weight: 1,
|
||||||
|
opacity: 0.7,
|
||||||
|
fillColor: '#256FFF',
|
||||||
|
fillOpacity: 0.2,
|
||||||
|
radius: 5000
|
||||||
|
}).addTo(map);
|
||||||
|
circle.bindPopup("Зона виміру");
|
||||||
},
|
},
|
||||||
beforeDestroy: function () {
|
beforeDestroy: function () {
|
||||||
this.ws.close();
|
this.ws.close();
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
if (localStorage.al) {
|
||||||
|
this.al = localStorage.al === "ok!";
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onmessage(ev) {
|
onmessage(ev) {
|
||||||
if (!this.rates_autoupdate) {
|
if (!this.rates_autoupdate) {
|
||||||
@ -161,4 +297,5 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -78,7 +78,7 @@ async def process(app):
|
|||||||
)
|
)
|
||||||
print(f'Rates updated, sending to {len(app.ws_clients)} connected clients')
|
print(f'Rates updated, sending to {len(app.ws_clients)} connected clients')
|
||||||
try:
|
try:
|
||||||
await asyncio.gather(*[ws.send_str(jdata) for ws in app.ws_clients], asyncio.sleep(1.0))
|
await asyncio.gather(*[ws.send_str(jdata) for ws in app.ws_clients], asyncio.sleep(2.0))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f'Error while sending to websocket: {e}')
|
print(f'Error while sending to websocket: {e}')
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user