Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Scriptable iOS Server Status Widget
const initialData = {
servers: [
{
url: 'https://1.example.com/',
title: 'Server 1',
online: null,
},
{
url: 'https://2.example.com/',
title: 'Server 2',
online: null,
},
{
url: 'https://3.example.com/',
title: 'Server 3',
online: null,
},
],
lastUpdate: null
}
// Refresh Interval in seconds
const refreshInterval = 300
const widget = await createWidget()
if (!config.runsInWidget) {
await widget.presentSmall()
}
Script.setWidget(widget)
Script.complete()
async function createWidget(items) {
const data = await refresh()
const list = new ListWidget()
// uncomment the lines below if you want to show the header (not working with more than ~5 servers)
// const header = list.addText("Server Status")
// header.font = Font.mediumSystemFont(13)
// list.addSpacer()
data.servers.forEach((server) => {
const label = list.addText((server.online ? '🟢' : (server.online === false ? '🔴' : '❔')) + ' ' + server.title)
label.font = Font.boldSystemFont(12)
label.textColor = Color.gray()
list.refreshAfterDate = new Date(Date.now() + refreshInterval)
list.addSpacer(3)
})
if (data.lastUpdate) {
list.addSpacer()
const lastRefreshLabel = list.addText('Last refresh: ' + data.lastUpdate)
lastRefreshLabel.font = Font.mediumSystemFont(8)
}
return list
}
async function refresh() {
let data = initialData
for (let server of data.servers) {
try {
let response = await new Request(server.url).loadString()
server.online = response && response.length > 0
} catch (e) {
server.online = false
}
}
let now = new Date()
let hours = now.getHours()
let mins = now.getMinutes()
data.lastUpdate = (hours > 9 ? hours : '0' + hours) + ':' + (mins > 9 ? mins : '0' + mins)
return data
}
@mIgU0815

This comment has been minimized.

Copy link

@mIgU0815 mIgU0815 commented Oct 24, 2020

hello, what struck me, a time out is missing ... if a page / server cannot be reached, the request runs for a very long time until the iOS time out comes. can you build in your own time out here and configure it with repetition?
for example: error if there is no answer for more than 15 seconds after 3 repetitions?
I adjusted the code a little ...
but I like it a lot and is simply built

#######
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: purple; icon-glyph: laptop;
const initialData = {
	servers: [
		{
			url: 'https://zellerberg.net/',
			title: 'Zellerberg.net',
			online: null,
		},
		{
			url: 'http://migu.mine.nu/',
			title: 'migu.mine.nu',
			online: null,
		},
		{
			url: 'http://zellerberg.homeip.net/',
			title: 'HomeIP',
			online: null,
		},
		{
			url: 'http://fritz.box/',
			title: 'fritz.box',
			online: null,
		},
	],
	lastUpdate: null
}

// Refresh Interval in seconds
const refreshInterval = 301

const widget = await createWidget()

if (!config.runsInWidget) {
	await widget.presentSmall()
}

Script.setWidget(widget)
Script.complete()

async function createWidget(items) {
	const data = await refresh()
	const list = new ListWidget()
// BackGroundColor
const gradient = new LinearGradient();
gradient.locations = [0, 1];
gradient.colors = [new Color('#2D1925'), new Color('#402938')];
list.backgroundGradient = gradient;
//
	//	uncomment the lines below if you want to show the header (not working with more than ~5 servers)

	const header = list.addText("Server Status")
    header.font = Font.mediumSystemFont(13)
    header.textColor = Color.white()
	list.addSpacer()

	data.servers.forEach((server) => {
		const label = list.addText((server.online ? '💚' : (server.online === false ? '💔' : '❔')) + ' ' + server.title)
		label.font = Font.boldSystemFont(12)
		label.textColor = Color.white()
		list.refreshAfterDate = new Date(Date.now() + refreshInterval)
		list.addSpacer(3)
	})

	if (data.lastUpdate) {
		list.addSpacer()
		const lastRefreshLabel = list.addText('Last refresh: ' + data.lastUpdate)
        lastRefreshLabel.font = Font.mediumSystemFont(8)
        lastRefreshLabel.textColor = Color.white()
	}

	return list
}

async function refresh() {
	let data = initialData

	for (let server of data.servers) {
		try {
			let response = await new Request(server.url).loadString()
			server.online = response && response.length > 0
		} catch (e) {
			server.online = false
		}
	}

	let now = new Date()

	let hours = now.getHours()
	let mins = now.getMinutes()
	let secs = now.getSeconds()
	data.lastUpdate = (hours > 9 ? hours : '0' + hours) + ':' + (mins > 9 ? mins : '0' + mins) + ':' + (secs > 9 ? secs : '0' + secs)
	return data
}

@dioncodes

This comment has been minimized.

Copy link
Owner Author

@dioncodes dioncodes commented Oct 27, 2020

Thanks for sharing! A timeout would be great indeed, unfortunately I didn't find anything in the Scriptable docs at the first sight using the default methods… Not sure if it's possible to perform own http requests there, but I might check that out. Also the string response comparison is not really nice. I tried to check the http status code using load() instead of loadString() but couldn't get any useful response from there.

@MrTheFirst

This comment has been minimized.

Copy link

@MrTheFirst MrTheFirst commented Oct 30, 2020

I a'm added push notifications for down servers and add HTTP status codes from response.

const initialData = {
  servers: [
    {
      url: 'https://server1.com/',
      title: 'server1',
      online: null,
    },
    {
      url: 'https://server2.com/',
      title: 'server2',
      online: null,
    },
  ],
  lastUpdate: null
}

// Refresh Interval in seconds
const refreshInterval = 300

const widget = await createWidget()

if (!config.runsInWidget) {
  await widget.presentLarge()
}

Script.setWidget(widget)
Script.complete()

async function createWidget(items) {
  const data = await refresh()
  const list = new ListWidget()

//	uncomment the lines below if you want to show the header (not working with more than ~5 servers)

// 	const header = list.addText("Server Status")
//  	header.font = Font.mediumSystemFont(13)
//  	list.addSpacer()

  await data.servers.forEach((server) => {
    let status = '';
    if (String(server.online).indexOf('20') !== -1 || String(server.online).indexOf('30') !== -1) {
      status = '🟢 ' + server.online + ' ' + server.title
    } else {
      status = '🔴 ' + server.online + ' ' + server.title
      sendNotification(server)
    }
    const label = list.addText(status)
    label.font = Font.boldSystemFont(12)
    label.textColor = Color.gray()
    list.refreshAfterDate = new Date(Date.now() + refreshInterval)
    list.addSpacer(3)
  })

  if (data.lastUpdate) {
    list.addSpacer()
    const lastRefreshLabel = list.addText('Last refresh: ' + data.lastUpdate)
    lastRefreshLabel.font = Font.mediumSystemFont(8)
  }

  return list
}

async function refresh() {
  let data = initialData

  for (let server of data.servers) {
    let request = new Request(server.url)
    request.method = 'GET'
    try {
      await request.load()
      server.online = request.response.statusCode
    } catch (response) {
      server.online = 0
    }
  }

  let now = new Date()

  let hours = now.getHours()
  let mins = now.getMinutes()

  data.lastUpdate = (hours > 9 ? hours : '0' + hours) + ':' + (mins > 9 ? mins : '0' + mins)
  return data
}
async function sendNotification(server) {
  let alert = new Notification()
  alert.sound = 'failure'
  alert.title = 'Server down'
  alert.body = 'Status of server "' + server.title + '" is ' + server.online
  alert.openURL = server.url
  await alert.schedule()
}
@dioncodes

This comment has been minimized.

Copy link
Owner Author

@dioncodes dioncodes commented Oct 30, 2020

I a'm added push notifications for down servers and add HTTP status codes from response.

@MrTheFirst Thanks, this is a great extension to the initial script. Would you mind if I adopt your notification functionality in the gist?

@MrTheFirst

This comment has been minimized.

Copy link

@MrTheFirst MrTheFirst commented Nov 2, 2020

@MrTheFirst Thanks, this is a great extension to the initial script. Would you mind if I adopt your notification functionality in the gist?

Of course use it! I just used the notification from the documentation. But I noticed an error in my script, if the server is not available, then a lot of notifications come (it seems as much as there are servers in the settings). This is because of the asynchronous functions in the loops.

@Sergey20482048

This comment has been minimized.

Copy link

@Sergey20482048 Sergey20482048 commented Nov 9, 2020

I wanted to add ip addresses instead of http and for some reason it doesn't work. Help me how to do this?

@tommyd75

This comment has been minimized.

Copy link

@tommyd75 tommyd75 commented Nov 30, 2020

@Sergey20482048 I used the above script with IP addresses by just using http://192.168.1.1/ in the server line , but my servers have a web page that you land on when you navigate to that IP. I'm not sure if yours are running a web server..

Does anyone know how to make this script use two columns so I can squeeze in two columns of 4 servers each?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment