initial commit

This commit is contained in:
apoc 2021-02-11 01:00:47 +01:00
commit 1466bf2c8e
Signed by: apoc
GPG Key ID: FB5C4A681CCD5FB2
2 changed files with 258 additions and 0 deletions

229
chaospott_mumble.js Normal file
View File

@ -0,0 +1,229 @@
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: yellow; icon-glyph: magic;
const mumbleApiUrl = "https://apoc.uber.space/chaospott_mumble.json";
const spaceApiUrl = "https://status.chaospott.de/status.json";
const logoUrl = "https://chaospott.de/images/logo.png";
const logoLocalFilename = "chaospott_logo.png";
const mumbleLocalFilename = "chaospott_mumble.json";
const spaceLocalFilename = "chaospott_space.json";
const title = "Chaospott";
const subTitle = "Essen";
var colorSpaceClosed;
var colorSpaceOpen;
var widget = await createWidget();
if (!config.runsInWidget) {
await widget.presentSmall();
}
Script.setWidget(widget);
Script.complete();
async function createWidget(){
const colorOpenFresh = Color.green();
const colorOpenStale = new Color("#00ff00", 0.3);
const colorClosedFresh = new Color("#ff0000", 1.0);
const colorClosedStale = new Color("#ff0000", 0.3);
const colorLonelyFresh = new Color("#ff8800", 1.0);
const colorLonelyStale = new Color("#ff8800", 0.3);
var colorBorderOpen = colorOpenFresh;
var colorBorderClosed = colorClosedFresh;
var colorBorderLonely = colorLonelyFresh;
var colorMumbleOpen;
var colorMumbleClosed;
var colorMumbleLonely;
const widget = new ListWidget();
try {
var [mumbleStatus, mumbleFresh] = await getJSONandCache(mumbleLocalFilename, mumbleApiUrl);
var [spaceStatus, spaceFresh] = await getJSONandCache(spaceLocalFilename, spaceApiUrl);
} catch(err) {
const errorList = new ListWidget();
errorList.addText("Please enable internet for initial execution.");
return errorList;
}
if (mumbleFresh){
colorMumbleOpen = colorOpenFresh;
colorMumbleClosed = colorClosedFresh;
colorMumbleLonely = colorLonelyFresh;
} else {
colorMumbleOpen = colorOpenStale;
colorMumbleClosed = colorClosedStale;
colorMumbleLonely = colorLonelyStale;
colorBorderOpen = colorOpenStale;
colorBorderClosed = colorClosedStale;
colorBorderLonely = colorLonelyStale;
}
if (spaceFresh){
colorSpaceOpen = colorOpenFresh;
colorSpaceClosed = colorClosedFresh;
} else {
colorSpaceOpen = colorOpenStale;
colorSpaceClosed = colorClosedStale;
colorBorderOpen = colorOpenStale;
colorBorderClosed = colorClosedStale;
colorBorderLonely = colorLonelyStale;
}
if (spaceStatus.state.open){
widget.backgroundColor = colorBorderOpen;
} else {
switch(mumbleStatus.connected_users){
case 0:
widget.backgroundColor = colorBorderClosed;
break;
case 1:
widget.backgroundColor = colorBorderLonely;
break;
default:
widget.backgroundColor = colorBorderOpen;
}
}
widget.setPadding(0, 5, 0, 5);
canvasStack = widget.addStack();
canvasStack.setPadding(5, 15, 5, 15);
canvasStack.cornerRadius = 15;
canvasStack.layoutVertically();
canvasStack.backgroundColor = Color.dynamic(Color.white(), Color.black());
const headerStack = canvasStack.addStack();
const titleStack = headerStack.addStack();
titleStack.layoutVertically();
const titleText = titleStack.addText(title);
titleText.font = Font.regularSystemFont(16);
const subTitleText = titleStack.addText(subTitle);
subTitleText.font = Font.mediumSystemFont(10);
headerStack.addSpacer(5);
let logo = await getCachedImage(logoLocalFilename, logoUrl);
const logoImage = headerStack.addImage(logo);
logoImage.imageSize = new Size(30, 30);
canvasStack.addSpacer(5);
const middleRow = canvasStack.addStack();
spaceStatus.sensors.door_locked.forEach((obj,i,arr) => {
spaceView(middleRow, obj.location, obj.value);
if(i !== arr.length - 1){middleRow.addSpacer();}
});
const spaceLastUpdate = new Date(spaceStatus.state.lastchange*1000);
const spaceLastUpdateStack = canvasStack.addStack();
let spaceLastUpdateLabel = spaceLastUpdateStack.addDate(spaceLastUpdate);
spaceLastUpdateLabel.font = Font.mediumSystemFont(6);
spaceLastUpdateLabel.applyRelativeStyle();
const bottomRow = canvasStack.addStack();
bottomRow.useDefaultPadding();
bottomRow.centerAlignContent();
const mumbleLabelStack = bottomRow.addStack();
mumbleLabelStack.layoutVertically();
const labelMumble = mumbleLabelStack.addText("Mumble");
labelMumble.font = Font.regularSystemFont(14);
let mumbleLastUpdate = new Date(mumbleStatus.last_update * 1000 );
const labelMumbleUpdated = mumbleLabelStack.addDate(mumbleLastUpdate);
labelMumbleUpdated.font = Font.mediumSystemFont(6);
labelMumbleUpdated.applyTimeStyle();
bottomRow.addSpacer(23);
const mumbleValueStack = bottomRow.addStack();
const labelMumbleUser = mumbleValueStack.addText(mumbleStatus.connected_users.toString(10));
labelMumbleUser.font = Font.boldSystemFont(30);
switch(mumbleStatus.connected_users){
case 0:
labelMumbleUser.textColor = colorMumbleClosed;
break;
case 1:
labelMumbleUser.textColor = colorMumbleLonely;
break;
default:
labelMumbleUser.textColor = colorMumbleOpen;
}
canvasStack.addSpacer(4)
dateStack = canvasStack.addStack();
dateStack.layoutHorizontally();
dateStack.bottomAlignContent();
dateStack.addSpacer(41);
const now = new Date();
const timeLabel = dateStack.addDate(now)
timeLabel.font = Font.mediumSystemFont(10)
timeLabel.centerAlignText()
timeLabel.applyTimeStyle()
timeLabel.textColor = Color.darkGray()
return widget;
}
function spaceView(widget, space, lockStatus) {
const viewStack = widget.addStack();
viewStack.layoutVertically();
viewStack.centerAlignContent();
const spaceName = space.charAt(0).toUpperCase() + space.slice(1)
const label = viewStack.addText(spaceName);
label.font = Font.regularSystemFont(14);
const lock = SFSymbol.named("lock." + (lockStatus ? "" : "open.") + "fill");
lock.applyFont(Font.systemFont(20));
const lockImage = viewStack.addImage(lock.image);
lockImage.resizable = false;
lockImage.imageSize = new Size(25, 25);
if(lockStatus){
lockImage.tintColor = colorSpaceClosed;
} else {
lockImage.tintColor = colorSpaceOpen;
}
}
async function getCachedImage(localFilename, url) {
let fm = FileManager.local();
let dir = fm.cacheDirectory();
let path = fm.joinPath(dir, localFilename);
if (fm.fileExists(path)) {
return fm.readImage(path);
} else {
let r = new Request(url);
try {
let returnImage = await r.loadImage();
fm.writeImage(path, returnImage);
return returnImage;
} catch (err) {
// return placeholder
return SFSymbol.named("photo").image;
}
}
}
async function getJSONandCache(localFilename, url){
let fm = FileManager.local()
let dir = fm.cacheDirectory()
let path = fm.joinPath(dir, localFilename)
let r = new Request(url)
try {
var data = await r.loadJSON()
fm.writeString(path, JSON.stringify(data, null, 2))
var fresh = true;
} catch (err) {
if (fm.fileExists(path)) {
data = JSON.parse(fm.readString(path), null)
fresh = false;
} else {
throw "no data";
}
}
return [data, fresh];
}

29
chaospott_mumble.py Executable file
View File

@ -0,0 +1,29 @@
#!/usr/bin/env python
# -*- coding: utf-8
from struct import *
import socket, time, datetime, sys, json
try:
host = "mumble.chaospott.de"
port = 64738
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(1)
buf = pack(">iQ", 0, datetime.datetime.now().microsecond)
s.sendto(buf, (host, port))
try:
data, addr = s.recvfrom(1024)
except socket.timeout:
print("%d:NaN:NaN" % (time.time()))
sys.exit()
r = unpack(">bbbbQiii", data)
version = "%d.%d.%d" % (r[1], r[2], r[3])
last_update = int(time.time())
output = { "server_version": version, "connected_users": r[5], "max_users": r[6], "bandwidth": r[7], "last_update": last_update}
print(json.dumps(output))
except:
pass