first commit

This commit is contained in:
Fionera 2022-06-16 20:59:37 +02:00
commit 9081a1bc2c
6 changed files with 2042 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.idea
*.iml
target/

1800
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

21
Cargo.toml Normal file
View File

@ -0,0 +1,21 @@
[package]
name = "ctdo-status"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix-web = "4.0.0"
askama = "0.11.0"
serde_json = "1.0.81"
spaceapi = "0.8.1"
paho-mqtt = "0.11"
futures = "0.3"
futures-timer = "3.0"
async-channel = "1.6"
async-std = "1"
[build-dependencies]
askama = "0.11.0"

75
src/main.rs Normal file
View File

@ -0,0 +1,75 @@
use std::time::Duration;
use paho_mqtt as mqtt;
use futures::{executor::block_on, stream::StreamExt};
use actix_web::{App, get, HttpServer, Responder};
use serde_json;
use status::*;
mod status;
#[get("/api/spaceapi/v13")]
async fn api_spaceapi_v13() -> impl Responder {
serde_json::to_string(&build_status_v13())
}
#[get("/api/spaceapi/v14")]
async fn api_spaceapi_v14() -> impl Responder {
serde_json::to_string(&build_status_v14())
}
const TOPICS: &[&str] = &["/status/flukso/powerinW"];
const QOS: &[i32] = &[1];
#[tokio::main] // or
async fn main() -> std::io::Result<()> {
let create_opts = mqtt::CreateOptionsBuilder::new()
.server_uri("mqtt.ctdo.de")
.client_id("ctdo-status")
.finalize();
let mut cli = mqtt::AsyncClient::new(create_opts).expect("Error creating the client");
if let Err(err) = block_on(async {
// Get message stream before connecting.
let mut strm = cli.get_stream(25);
// Define the set of options for the connection
let conn_opts = mqtt::ConnectOptionsBuilder::new()
.keep_alive_interval(Duration::from_secs(30))
.mqtt_version(mqtt::MQTT_VERSION_3_1_1)
.clean_session(false)
.finalize();
println!("Connecting to the MQTT server...");
cli.connect(conn_opts).await?;
println!("Subscribing to topics: {:?}", TOPICS);
cli.subscribe_many(TOPICS, QOS).await?;
while let Some(msg_opt) = strm.next().await {
if let Some(msg) = msg_opt {
println!("{}", msg);
} else {
println!("Lost connection. Attempting reconnect.");
while let Err(err) = cli.reconnect().await {
println!("Error reconnecting...");
tokio::time::delay_for(Duration::from_millis(1000)).await;
}
}
}
Ok::<(), mqtt::Error>(())
}) {
panic!("{}", err);
}
HttpServer::new(|| {
App::new()
.service(api_spaceapi_v13)
.service(api_spaceapi_v14)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}

66
src/status.rs Normal file
View File

@ -0,0 +1,66 @@
use spaceapi::{Contact, Feed, Feeds, Icon, IssueReportChannel, Location, State, Status, StatusBuilder};
fn fetch_room_state() -> Option<bool> {
None
}
pub fn build_status_v13() -> Status {
build_status(StatusBuilder::v0_13)
.add_issue_report_channel(IssueReportChannel::Ml)
.add_issue_report_channel(IssueReportChannel::IssueMail)
.build()
.expect("Creating status failed")
}
pub fn build_status_v14() -> Status {
build_status(StatusBuilder::v14)
.build()
.expect("Creating status failed")
}
fn build_status(builder: fn(String) -> StatusBuilder) -> StatusBuilder {
builder("Chaostreff Dortmund".into())
.logo("https://www.chaostreff-dortmund.de/presse/logo/logo_ctdo.png")
.url("https://www.chaostreff-dortmund.de/")
.state(State {
open: fetch_room_state(),
icon: Some(Icon {
open: "https://status.ctdo.de/img/green.png".into(),
close: "https://status.ctdo.de/img/red.png".into(),
}),
..State::default()
})
.location(
Location {
address: Some("Braunschweiger Str 22, 44145 Dortmund, Germany".into()),
lat: 51.527611,
lon: 7.4649449,
})
.contact(
Contact {
phone: Some("+49 231 8 404 777".into()),
irc: Some("irc://irc.hackint.eu/#ccc.do".into()),
ml: Some("discuss@lists.chaostreff-dortmund.de".into()),
twitter: Some("@ctdo".into()),
issue_mail: Some("vorstand@chaostreff-dortmund.de".into()),
matrix: Some("#ccc.do:hackint.org".into()),
..Default::default()
})
.feeds(Feeds {
blog: Some(Feed {
url: "https://www.chaostreff-dortmund.de".into(),
..Feed::default()
}),
calendar: Some(Feed {
url: "https://www.chaostreff-dortmund.de/kalender/".into(),
..Feed::default()
}),
wiki: Some(Feed {
url: "https://wiki.chaostreff-dortmund.de".into(),
..Feed::default()
}),
..Feeds::default()
})
}

77
templates/index.html Normal file
View File

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="de">
<head><title>Home - CTDO Raumstatus</title>
<script type="text/javascript" src="/js/vendor/angular.min.js"></script>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<link rel="stylesheet" href="/css/ink-min.css">
<link rel="stylesheet" href="/css/rickshaw.min.css">
<link rel="stylesheet" href="/css/style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
</head>
<body>
<div class="ink-grid">
<header><h1>chaostreff status</h1></header>
<div class="main-content">
<div class="intro"><p>Hier siehst du den aktuellen Status von uns. Die Daten werden vom Router und unserem
Flukso
eingesammelt. Die Anzahl der Geräte und der Status selber werden Minütlich abgefragt. Unseren
Energieverbrauch bekommst du alle fünf Sekunden neu. Den Status "geöffnet" oder "geschlossen"
bestimmt das Programm mit einem ping auf den Switch im Raum. Mit dem Knopf unter dem Stromverbrauch
kannst du einschalten, dass du eine Benachrichtigung bei einer Änderung bekommst. Der Tab muss dafür offen
bleiben.</p></div>
<div ng-controller="StatusCtrl" class="ink-grid">
<div class="column-group gutters">
<div class="large-20 medium-20 small-100">
<div class="status-icon status-icon-{{simple.state}}"></div>
<dl>
<dt>aktueller Status:</dt>
<dd>{{simple.state | statustostring}}</dd>
<dt>letzte Abfrage:</dt>
<dd>{{simple.lastchange | date:'dd.MM.yyyy HH:mm:ss'}}
<dt>aktive Ger&auml;te:</dt>
<dd>{{simple.count}}</dd>
</dd></dl>
</div>
<div class="large-50 medium-80 small-100"><h2>Anzahl Geräte im LAN:</h2>
<div id="graph"></div>
<h2>Personen anwesend:</h2><span ng-repeat="name in simple.names">{{name}}<span ng-show=" ! $last ">,
<!-- --></span></span></div>
<div class="large-30 medium-100 small-100"><h2>Energieverbrauch</h2>
<div id="gauge" class="power"></div>
<button type="button" onclick="toggle();" id="notificationButton" class="btn btn-block btn-danger">
Statusbenachrichtigungen aus
</button>
</div>
</div>
</div>
</div>
<footer>
<nav class="ink-navigation">
<ul class="menu horizontal">
<li><a href="/">Raumstatus</a></li>
<li><a href="//www.chaostreff-dortmund.de/">CTDO Webseite</a></li>
<li><a href="//wiki.ctdo.de/">CTDO Wiki</a></li>
<li><a href="https://repos.ctdo.de/ctdo/raumstatus/tree/master">Source</a></li>
</ul>
</nav>
</footer>
</div>
<script type="text/javascript" src="/js/vendor/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="/js/vendor/ink.min.js"></script>
<script type="text/javascript" src="/js/vendor/autoload.js"></script>
<script type="text/javascript" src="/js/vendor/html5shiv.js"></script>
<script type="text/javascript" src="/js/vendor/prettify.js"></script>
<script type="text/javascript" src="/js/vendor/modernizr.js"></script>
<script type="text/javascript" src="/js/app.js"></script>
<script type="text/javascript" src="/js/vendor/cheet.min.js"></script>
<script type="text/javascript" src="/js/vendor/notification.js"></script>
<script type="text/javascript" src="/js/easter.js"></script>
<script type="text/javascript" src="/js/vendor/d3.min.js"></script>
<script type="text/javascript" src="/js/vendor/d3.layout.min.js"></script>
<script type="text/javascript" src="/js/vendor/rickshaw.min.js"></script>
<script type="text/javascript" src="/js/vendor/moment.min.js"></script>
<script type="text/javascript" src="/js/graph.js"></script>
<script type="text/javascript" src="/js/vendor/raphael.2.1.0.min.js"></script>
<script type="text/javascript" src="/js/vendor/justgage.1.0.1.min.js"></script>
</body>
</html>