initial commit
This commit is contained in:
commit
1466bf2c8e
229
chaospott_mumble.js
Normal file
229
chaospott_mumble.js
Normal 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
29
chaospott_mumble.py
Executable 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
|
Loading…
Reference in New Issue
Block a user