Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Variables used by Scriptable.
- // These must be at the very top of the file. Do not edit.
- // icon-color: green; icon-glyph: magic;
- // Welcome! This script shows basic infos about your Homebridge installation
- // All infos shown are based and provided by the Homebridge Config UI X found at https://github.com/oznu/homebridge-config-ui-x
- // Thanks to the github user oznu for providing such a nice programm!
- // This script does not work if you don't have the Homebridge service (Homebridge Config UI X) running
- // This script was developed with Homebridge Config UI X in version 4.32.0 (2020-11-06) and Scriptable app in version 1.6.1 on iOS 14.2
- // Maybe you need to update the UI-service OR the Scriptable app OR your iPhone if this script does not work for you
- // CONFIGURATION //////////////////////
- // you must at least configure the next 3 lines to make this script work
- const hbServiceMachineBaseUrl = 'http://192.168.1.107'; // location of your system running the hb-service, e.g. http://192.168.178.33:8581
- const userName = 'admin'; // username of administrator of the hb-service
- const password = 'admin'; // password of administrator of the hb-service
- const systemGuiName = 'Server'; // name of the system your service is running on
- const fileManagerMode = 'ICLOUD'; // default is ICLOUD. If you don't use iCloud Drive use option LOCAL
- const temperatureUnitConfig = 'CELSIUS'; // options are CELSIUS or FAHRENHEIT
- const requestTimeoutInterval = 1; // in seconds; If requests take longer, the script is stopped. Increase it if it doesn't work or you
- const decimalChar = ','; // if you like a dot as decimal separator make the comma to a dot here
- const maxLineWidth = 310; // if layout doesn't look good for you,
- const normalLineHeight = 35; // try to tweak the (font-)sizes & remove/add spaces below
- // CONFIGURATION END //////////////////////
- const authUrl = hbServiceMachineBaseUrl + '/api/auth/login';
- const cpuUrl = hbServiceMachineBaseUrl + '/api/status/cpu';
- const hbStatusUrl = hbServiceMachineBaseUrl + '/api/status/homebridge';
- const ramUrl = hbServiceMachineBaseUrl + '/api/status/ram';
- const uptimeUrl = hbServiceMachineBaseUrl + '/api/status/uptime';
- const pluginsUrl = hbServiceMachineBaseUrl + '/api/plugins';
- const hbVersionUrl = hbServiceMachineBaseUrl + '/api/status/homebridge-version';
- const nodeJsUrl = hbServiceMachineBaseUrl + '/api/status/nodejs';
- // logo is downloaded only the first time! It is saved in iCloud and then loaded from there everytime afterwards
- const logoUrl = 'https://github.com/homebridge/branding/blob/master/logos/homebridge-outline-black.png?raw=true';
- const timeFormatter = new DateFormatter();
- timeFormatter.dateFormat = 'dd.MM. HH:mm';
- const headerFont = Font.boldMonospacedSystemFont(12);
- const monospacedHeaderFont = Font.lightMonospacedSystemFont(12);
- const infoFont = Font.systemFont(10);
- const heavyInfoFont = Font.heavySystemFont(10);
- const chartAxisFont = Font.systemFont(7);
- const updatedAtFont = Font.boldSystemFont(10);
- const fontColorWhite = new Color("#FFFFFF");
- const bgColorPurple = new Color("#421367");
- const lin= new LinearGradient()
- lin.colors=[Color.black(), new Color("1e1e1e"),new Color("242424")]
- lin.locations =[0,0.5,1]
- const chartColor = Color.darkGray()
- const iconColor = Color.dynamic(Color.black(), Color.white());
- const UNAVAILABLE = 'UNAVAILABLE';
- class LineChart {
- // LineChart by https://kevinkub.de/
- // taken from https://gist.github.com/kevinkub/b74f9c16f050576ae760a7730c19b8e2
- constructor(width, height, values) {
- this.ctx = new DrawContext();
- this.ctx.size = new Size(width, height);
- this.values = values;
- }
- _calculatePath() {
- let maxValue = Math.max(...this.values);
- let minValue = Math.min(...this.values);
- let difference = maxValue - minValue;
- let count = this.values.length;
- let step = this.ctx.size.width / (count - 1);
- let points = this.values.map((current, index, all) => {
- let x = step * index;
- let y = this.ctx.size.height - (current - minValue) / difference * this.ctx.size.height;
- return new Point(x, y);
- });
- return this._getSmoothPath(points);
- }
- _getSmoothPath(points) {
- let path = new Path();
- path.move(new Point(0, this.ctx.size.height));
- path.addLine(points[0]);
- for (let i = 0; i < points.length - 1; i++) {
- let xAvg = (points[i].x + points[i + 1].x) / 2;
- let yAvg = (points[i].y + points[i + 1].y) / 2;
- let avg = new Point(xAvg, yAvg);
- let cp1 = new Point((xAvg + points[i].x) / 2, points[i].y);
- let next = new Point(points[i + 1].x, points[i + 1].y);
- let cp2 = new Point((xAvg + points[i + 1].x) / 2, points[i + 1].y);
- path.addQuadCurve(avg, cp1);
- path.addQuadCurve(next, cp2);
- }
- path.addLine(new Point(this.ctx.size.width, this.ctx.size.height));
- path.closeSubpath();
- return path;
- }
- configure(fn) {
- let path = this._calculatePath();
- if (fn) {
- fn(this.ctx, path);
- } else {
- this.ctx.addPath(path);
- this.ctx.fillPath(path);
- }
- return this.ctx;
- }
- }
- // WIDGET INIT //////////////////////
- let widget = await createWidget();
- if (!config.runsInWidget) {
- await widget.presentMedium();
- }
- Script.setWidget(widget);
- Script.complete();
- // WIDGET INIT END //////////////////////
- async function createWidget() {
- // authenticate against the hb-service
- let token = await getAuthToken();
- let widget = new ListWidget();
- //widget.backgroundColor = bgColorPurple;
- // widget.backgroundGradient=lin
- if (token !== UNAVAILABLE) {
- widget.addSpacer(10);
- }
- // LOGO AND HEADER //////////////////////
- let titleStack = widget.addStack();
- titleStack.centerAlignContent()
- //titleStack.size = new Size(maxLineWidth, normalLineHeight);
- const logo = await getHbLogo();
- const imgWidget = titleStack.addImage(logo);
- imgWidget.tintColor = iconColor
- imgWidget.imageSize = new Size(40, 30);
- titleStack.addSpacer(5)
- headerStack= titleStack.addStack()
- headerStack.layoutVertically()
- let headerText = headerStack.addText('Homebridge ');
- headerText.font = headerFont;
- headerText.size = new Size(60, normalLineHeight);
- // headerText.textColor = fontColorWhite;
- let updatedAt = headerStack.addText('Status:');
- updatedAt.font = updatedAtFont;
- // updatedAt.textColor = fontColorWhite;
- updatedAt.centerAlignText();
- updatedAt = headerStack.addText(timeFormatter.string(new Date()));
- updatedAt.font = updatedAtFont;
- // updatedAt.textColor = fontColorWhite;
- updatedAt.centerAlignText();
- // LOGO AND HEADER END //////////////////////
- if (token === UNAVAILABLE) {
- // script ends after the next line
- return addNotAvailableInfos(widget, titleStack);
- }
- // fetch all the data necessary
- let hbStatus = await getHomebridgeStatus(token);
- let hbUpToDate = await getHomebridgeUpToDate(token);
- let pluginsUpToDate = await getPluginsUpToDate(token);
- let nodeJsUpToDate = await getNodeJsUpToDate(token);
- let cpuData = await fetchData(token, cpuUrl);
- let ramData = await fetchData(token, ramUrl);
- let usedRamText = await getUsedRamString(ramData);
- let uptimeText = await getUptimeString(token);
- // STATUS PANEL IN THE HEADER //////////////////////
- titleStack.addSpacer(30)
- let statusInfo = titleStack.addStack()
- //statusInfo.size = new Size(145, 30);
- statusInfo.layoutVertically()
- line=statusInfo.addStack()
- //running
- item=line.addStack()
- item.centerAlignContent()
- addImageItem(hbStatus)
- item.addSpacer(2)
- addTextItem("Running")
- //UTd
- line.addSpacer()
- item=line.addStack()
- item.centerAlignContent()
- addImageItem(hbUpToDate)
- //addImageItem("❌")
- item.addSpacer(2)
- addTextItem("Homebridge")
- statusInfo.addSpacer(5)
- //item.addSpacer()
- line=statusInfo.addStack()
- //PluginsUTD
- item=line.addStack()
- item.centerAlignContent()
- addImageItem(pluginsUpToDate)
- item.addSpacer(2)
- addTextItem("Plugins")
- //Node.JS UD
- line.addSpacer()
- item=line.addStack()
- item.centerAlignContent()
- addImageItem(nodeJsUpToDate)
- item.addSpacer(2)
- addTextItem("Node.js")
- line.addSpacer(23)
- // .inaddText(hbStatus + 'Running ' + hbUpToDate + 'UTD\n' + pluginsUpToDate + 'Plugins UTD ' + nodeJsUpToDate + 'Node.js UTD');
- // statusInfo.font = monospacedHeaderFont;
- //
- // statusInfo.textColor = fontColorWhite;
- //
- // STATUS PANEL IN THE HEADER END //////////////////////
- widget.addSpacer(10);
- // CHART STACK START //////////////////////
- let s= widget.addStack()
- let l = s.addStack()
- let cpuLoadAndRamText= l.addText('CPU Load: ');
- cpuLoadAndRamText.font = heavyInfoFont;
- // cpuLoadAndRamText.textColor = fontColorWhite;
- cpuLoadAndRamText = l.addText(getAsRoundedString(cpuData.currentLoad, 1) + '%');
- cpuLoadAndRamText.font = infoFont;
- // cpuLoadAndRamText.textColor = fontColorWhite;
- s.addSpacer(70)
- l=s.addStack()
- l.addSpacer(5)
- cpuLoadAndRamText= l.addText('RAM Usage: ');
- cpuLoadAndRamText.font = heavyInfoFont;
- // cpuLoadAndRamText.textColor = fontColorWhite;
- cpuLoadAndRamText = l.addText(usedRamText + '%');
- cpuLoadAndRamText.font = infoFont;
- // cpuLoadAndRamText.textColor = fontColorWhite;
- widget.addSpacer(5)
- let chartStack = widget.addStack();
- chartStack.size = new Size(maxLineWidth, 30);
- let minMaxCpuLoadText = chartStack.addText(getMaxString(cpuData.cpuLoadHistory, 2) + '%\n\n' + getMinString(cpuData.cpuLoadHistory, 2) + '%');
- minMaxCpuLoadText.size = new Size(20, 10);
- minMaxCpuLoadText.font = chartAxisFont;
- // minMaxCpuLoadText.textColor = fontColorWhite;
- let cpuLoadChart = new LineChart(500, 100, cpuData.cpuLoadHistory).configure((ctx, path) => {
- ctx.opaque = false;
- ctx.setFillColor(chartColor);
- ctx.addPath(path);
- ctx.fillPath(path);
- }).getImage();
- let cpuLoadChartImage = chartStack.addImage(cpuLoadChart);
- cpuLoadChartImage.imageSize = new Size(110, 25);
- chartStack.addSpacer(25);
- let minMaxRamUsageText = chartStack.addText(getMaxString(ramData.memoryUsageHistory, 2) + '%\n\n' + getMinString(ramData.memoryUsageHistory, 2) + '%');
- minMaxRamUsageText.size = new Size(20, 10);
- minMaxRamUsageText.font = chartAxisFont;
- // minMaxRamUsageText.textColor = fontColorWhite;
- let ramUsageChart = new LineChart(500, 100, ramData.memoryUsageHistory).configure((ctx, path) => {
- ctx.opaque = false;
- ctx.setFillColor(chartColor);
- ctx.addPath(path);
- ctx.fillPath(path);
- }).getImage();
- let ramUsageChartImage = chartStack.addImage(ramUsageChart);
- ramUsageChartImage.imageSize = new Size(110, 25);
- chartStack.addSpacer()
- // CHART STACK END //////////////////////
- widget.addSpacer(3);
- // LOWER PART //////////////////////
- let row3Stack = widget.addStack();
- row3Stack.size = new Size(maxLineWidth, 30);
- l = row3Stack.addStack()
- cpuTempText = l.addText('CPU Temp: ');
- cpuTempText.font = heavyInfoFont;
- cpuTempText.size = new Size(150, 30);
- // cpuTempText.textColor = fontColorWhite;
- cpuTempText = l.addText(getTemperatureString(cpuData.cpuTemperature.main));
- cpuTempText.font = infoFont;
- cpuTempText.size = new Size(150, 30);
- // cpuTempText.textColor = fontColorWhite;
- l.addSpacer()
- l = row3Stack.addStack()
- let uptimeTitleTextRef = l.addText(' Uptimes: ');
- uptimeTitleTextRef.font = heavyInfoFont;
- // uptimeTitleTextRef.textColor = fontColorWhite;
- let uptimeTextRef = l.addText(uptimeText);
- uptimeTextRef.font = infoFont;
- // uptimeTextRef.textColor = fontColorWhite;
- l.addSpacer()
- // LOWER PART END //////////////////////
- widget.addSpacer();
- // BOTTOM UPDATED TEXT //////////////////////
- // let updatedAt = widget.addText('Updated: ' + timeFormatter.string(new Date()));
- // updatedAt.font = updatedAtFont;
- // updatedAt.textColor = fontColorWhite;
- // updatedAt.centerAlignText();
- // BOTTOM UPDATED TEXT END //////////////////////
- widget.url=hbServiceMachineBaseUrl
- return widget;
- }
- async function getAuthToken() {
- let req = new Request(authUrl);
- req.timeoutInterval = requestTimeoutInterval;
- let body = {
- "username": userName,
- "password": password,
- "otp": "string"
- };
- let headers = {
- "accept": "*\/*", "Content-Type": "application/json"
- };
- req.body = JSON.stringify(body);
- req.method = "POST";
- req.headers = headers;
- let authData;
- try {
- authData = await req.loadJSON();
- log(authData)
- } catch (e) {
- return UNAVAILABLE;
- }
- return authData.access_token;
- }
- async function fetchData(token, url) {
- let req = new Request(url);
- req.timeoutInterval = requestTimeoutInterval;
- let headers = {
- "accept": "*\/*", "Content-Type": "application/json",
- "Authorization": "Bearer " + token
- };
- req.headers = headers;
- return req.loadJSON();
- }
- async function getHomebridgeStatus(token) {
- const statusData = await fetchData(token, hbStatusUrl);
- return statusData.status === 'up' ? '✅' : '❌';
- }
- async function getHomebridgeUpToDate(token) {
- const hbVersionData = await fetchData(token, hbVersionUrl);
- log(hbVersionData.updateAvailable)
- return hbVersionData.updateAvailable ? '❌' : '✅';
- }
- async function getNodeJsUpToDate(token) {
- const nodeJsData = await fetchData(token, nodeJsUrl);
- return nodeJsData.updateAvailable ? '❌' : '✅';
- }
- async function getPluginsUpToDate(token) {
- const pluginsData = await fetchData(token, pluginsUrl);
- for (plugin of pluginsData) {
- if (plugin.updateAvailable) {
- return '❌';
- }
- }
- return '✅';
- }
- async function getUsedRamString(ramData) {
- return getAsRoundedString(100 - 100 * ramData.mem.available / ramData.mem.total, 1);
- }
- async function getUptimeString(token) {
- const uptimeData = await fetchData(token, uptimeUrl);
- let serverTime = uptimeData.time.uptime;
- let processUptime = uptimeData.processUptime;
- return systemGuiName + ':\t ' + formatMinutes(serverTime) + '\nUI-Service:\t ' + formatMinutes(processUptime);
- }
- function formatMinutes(value) {
- if (value > 60 * 60 * 24) {
- return getAsRoundedString(value / 60 / 60 / 24, 1) + 'd';
- } else if (value > 60 * 60) {
- return getAsRoundedString(value / 60 / 60, 1) + 'h';
- } else if (value > 60) {
- return getAsRoundedString(value / 60, 0) + 'm';
- } else {
- return getAsRoundedString(value, 2) + 's';
- }
- }
- async function loadImage(imgUrl) {
- let req = new Request(imgUrl);
- req.timeoutInterval = requestTimeoutInterval;
- let image = await req.loadImage();
- return image;
- }
- async function getHbLogo() {
- // fileManagerMode must be LOCAL if you do not use iCloud drive
- let fm = fileManagerMode === 'LOCAL' ? FileManager.local() : FileManager.iCloud();
- let path = getStoredLogoPath();
- if (fm.fileExists(path)) {
- return fm.readImage(path);
- } else {
- // logo did not exist -> download it and save it for next time the widget runs
- const logo = await loadImage(logoUrl);
- saveHbLogo(logo);
- return logo;
- }
- }
- function saveHbLogo(image) {
- // fileManagerMode must be LOCAL if you do not use iCloud drive
- let fm = fileManagerMode === 'LOCAL' ? FileManager.local() : FileManager.iCloud();
- let path = getStoredLogoPath();
- fm.writeImage(path, image);
- }
- function getStoredLogoPath() {
- // fileManagerMode must be LOCAL if you do not use iCloud drive
- let fm = fileManagerMode === 'LOCAL' ? FileManager.local() : FileManager.iCloud();
- let dirPath = fm.joinPath(fm.documentsDirectory(), "homebridgeStatus");
- if (!fm.fileExists(dirPath)) {
- fm.createDirectory(dirPath);
- }
- return fm.joinPath(dirPath, "hbLogo.png");
- }
- function addNotAvailableInfos(widget, titleStack) {
- let statusInfo = titleStack.addText(' ');
- statusInfo.textColor = fontColorWhite;
- statusInfo.size = new Size(150, normalLineHeight);
- let errorText = widget.addText(' ❌ UI-Service not reachable!\n 👉🏻 Server started?\n 👉🏻 UI-Service process started?\n 👉🏻 Server-URL ' + hbServiceMachineBaseUrl + ' correct?\n 👉🏻 Are you in the same network?');
- errorText.size = new Size(410, 130);
- errorText.font = infoFont;
- errorText.textColor = fontColorWhite;
- widget.addSpacer(15);
- let updatedAt = widget.addText('Updated: ' + timeFormatter.string(new Date()));
- updatedAt.font = updatedAtFont;
- updatedAt.textColor = fontColorWhite;
- updatedAt.centerAlignText();
- return widget;
- }
- function getAsRoundedString(value, decimals) {
- let factor = Math.pow(10, decimals);
- return (Math.round((value + Number.EPSILON) * factor) / factor).toFixed(1).replace('.', decimalChar);
- }
- function getMaxString(arrayOfNumbers, decimals) {
- let factor = Math.pow(10, decimals);
- return (Math.round((Math.max(...arrayOfNumbers) + Number.EPSILON) * factor) / factor).toString().replace('.', decimalChar);
- }
- function getMinString(arrayOfNumbers, decimals) {
- let factor = Math.pow(10, decimals);
- return (Math.round((Math.min(...arrayOfNumbers) + Number.EPSILON) * factor) / factor).toString().replace('.', decimalChar);
- }
- function getTemperatureString(temperatureInCelsius) {
- if (temperatureUnitConfig === 'FAHRENHEIT') {
- return getAsRoundedString(convertToFahrenheit(temperatureInCelsius), 1) + '°F';
- } else {
- return getAsRoundedString(temperatureInCelsius, 1) + '°C';
- }
- }
- function convertToFahrenheit(temperatureInCelsius) {
- return temperatureInCelsius * 9 / 5 + 32
- }
- function addTextItem(text){
- t=item.addText(text)
- t.font = Font.semiboldMonospacedSystemFont(10);
- //t.textColor = fontColorWhite;
- }
- function addImageItem(text){
- switch (text){
- case "✅" :
- name="checkmark.circle.fill"
- color=Color.green()
- break;
- case "❌":
- name="exclamationmark.triangle.fill"
- color=Color.red()
- }
- log(name)
- image = symbol(name)
- i=item.addImage(image)
- i.resizable=true
- i.imageSize=new Size(13,13)
- i.tintColor=color
- }
- function symbol(name){
- sf=SFSymbol.named(name)
- sf.applyFont(Font.heavySystemFont(50))
- return sf.image}
Advertisement
Add Comment
Please, Sign In to add comment