-
-
Save veeravat/a84fabc25c9e28077234ad7198acb562 to your computer and use it in GitHub Desktop.
Simple Home Assistant (HASS) iOS Widget via Scriptable App
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let widget = await createWidget(); | |
if (!config.runsInWidget) { | |
await widget.presentSmall(); | |
} | |
Script.setWidget(widget); | |
Script.complete(); | |
async function createWidget(items) { | |
/* Get data from API */ | |
const tempImg = await getImage('temperature.png'); | |
const humidImg = await getImage('humidity.png'); | |
const logoImg = await getImage('hass-favicon.png'); | |
let req = new Request("https://<HASS IP>/api/states") | |
req.headers = { "Authorization": "Bearer <HASS Long-Lived Access Token at https://<HASS IP>/profile", "content-type": "application/json" } | |
let json = await req.loadJSON(); | |
/* Parse data received from API */ | |
let data = {outdoor: {}, child: {}, office: {}, bedroom: {}, livingroom: {}, kitchen: {}, hallway: {}, bathroom: {}, wc: {}} | |
data.outdoor = addData(json, data.outdoor, ['sensor.ble_temperature_aabbccddeeff', 'sensor.ble_humidity_aabbccddeeff']); | |
data.child = addData(json, data.child, ['sensor.ble_temperature_aabbccddeeff', 'sensor.ble_humidity_aabbccddeeff']); | |
data.office = addData(json, data.office, ['sensor.ble_temperature_aabbccddeeff', 'sensor.ble_humidity_aabbccddeeff']); | |
data.bedroom = addData(json, data.bedroom, ['sensor.ble_temperature_aabbccddeeff', 'sensor.ble_humidity_aabbccddeeff']); | |
data.livingroom = addData(json, data.livingroom, ['sensor.ble_temperature_aabbccddeeff', 'sensor.ble_humidity_aabbccddeeff']); | |
data.kitchen = addData(json, data.kitchen, ['sensor.ble_temperature_aabbccddeeff', 'sensor.ble_humidity_aabbccddeeff']); | |
data.hallway = addData(json, data.hallway, ['sensor.ble_temperature_aabbccddeeff', 'sensor.ble_humidity_aabbccddeeff']); | |
data.bathroom = addData(json, data.bathroom, ['sensor.ble_temperature_aabbccddeeff', 'sensor.ble_humidity_aabbccddeeff']); | |
data.wc = addData(json, data.wc, ['sensor.ble_temperature_aabbccddeeff', 'sensor.ble_humidity_aabbccddeeff']); | |
/* Create the widget */ | |
const widget = new ListWidget(); | |
widget.backgroundColor = new Color("#03a9f4", 1.0); | |
/* Design the widget header */ | |
let headerStack = widget.addStack(); | |
const logoStack = headerStack.addStack(); | |
headerStack.addSpacer(2); | |
const titleStack = headerStack.addStack(); | |
headerStack.addSpacer(7); | |
const tempImageStack = headerStack.addStack(); | |
headerStack.addSpacer(14); | |
const humidImageStack = headerStack.addStack(); | |
/* Add a logo icon */ | |
logoStack.backgroundColor = new Color("#03a9f4", 1.0) | |
logoStack.cornerRadius = 1 | |
const wimgLogo = logoStack.addImage(logoImg) | |
wimgLogo.imageSize = new Size(20, 20) | |
wimgLogo.rightAlignImage() | |
/* Add the name of this Home Assistant */ | |
const titleLabel = titleStack.addText("HA42"); | |
titleStack.setPadding(2, 0, 0, 0); | |
titleLabel.font = Font.heavyMonospacedSystemFont(12); | |
titleLabel.textColor = Color.black(); | |
/* Add a temperature icon */ | |
tempImageStack.backgroundColor = new Color("#03a9f4", 1.0) | |
tempImageStack.cornerRadius = 1 | |
const wimgTemp = tempImageStack.addImage(tempImg) | |
wimgTemp.imageSize = new Size(20, 20) | |
wimgTemp.rightAlignImage() | |
/* Add a humid icon */ | |
humidImageStack.backgroundColor = new Color("#03a9f4", 1.0) | |
humidImageStack.cornerRadius = 1 | |
const wimgHumid = humidImageStack.addImage(humidImg) | |
wimgHumid.imageSize = new Size(20, 20) | |
wimgHumid.rightAlignImage() | |
widget.addSpacer(5) | |
/* Add the sensor entries */ | |
const bodyStack = widget.addStack(); | |
/* First, the label column */ | |
const labelStack = bodyStack.addStack(); | |
labelStack.setPadding(0, 0, 0, 0); | |
labelStack.borderWidth = 0; | |
labelStack.layoutVertically(); | |
addLabel(labelStack, " Outdoor:") | |
addLabel(labelStack, " Child:") | |
addLabel(labelStack, " Office:") | |
addLabel(labelStack, " Bedroom:") | |
addLabel(labelStack, " Living:") | |
addLabel(labelStack, " Kitchen:") | |
addLabel(labelStack, " Hallway:") | |
addLabel(labelStack, " Bathroom:") | |
addLabel(labelStack, " WC:") | |
/* Second, the temperature column */ | |
const tempStack = bodyStack.addStack(); | |
tempStack.setPadding(0, 3, 0, 0); | |
tempStack.borderWidth = 0; | |
tempStack.layoutVertically(); | |
addTemp(tempStack, data.outdoor) | |
addTemp(tempStack, data.child) | |
addTemp(tempStack, data.office) | |
addTemp(tempStack, data.bedroom) | |
addTemp(tempStack, data.livingroom) | |
addTemp(tempStack, data.kitchen) | |
addTemp(tempStack, data.hallway) | |
addTemp(tempStack, data.bathroom) | |
addTemp(tempStack, data.wc) | |
/* Third, the humidity column */ | |
const humidStack = bodyStack.addStack(); | |
humidStack.setPadding(0, 5, 0, 0); | |
humidStack.borderWidth = 0; | |
humidStack.layoutVertically(); | |
addHumid(humidStack, data.outdoor) | |
addHumid(humidStack, data.child) | |
addHumid(humidStack, data.office) | |
addHumid(humidStack, data.bedroom) | |
addHumid(humidStack, data.livingroom) | |
addHumid(humidStack, data.kitchen) | |
addHumid(humidStack, data.hallway) | |
addHumid(humidStack, data.bathroom) | |
addHumid(humidStack, data.wc) | |
/* Done: Widget is now ready to be displayed */ | |
return widget; | |
} | |
/* Adds the entries to the label column */ | |
async function addLabel(labelStack, label) { | |
const mytext = labelStack.addText(label); | |
mytext.font = Font.semiboldSystemFont(10); | |
mytext.textColor = Color.black(); | |
} | |
/* Adds the entries to the temperature column */ | |
async function addTemp(tempStack, data) { | |
const mytext = tempStack.addText(data.temp + "°C"); | |
mytext.font = Font.heavyMonospacedSystemFont(10); | |
mytext.textColor = Color.white(); | |
} | |
/* Adds the entries to the humidity column */ | |
async function addHumid(humidStack, data) { | |
const mytext = humidStack.addText("(" + data.humid + "%)"); | |
mytext.font = Font.mediumMonospacedSystemFont(10); | |
mytext.textColor = Color.white(); | |
mytext.textOpacity = 0.8; | |
} | |
/* | |
The following function is "borrowed" from: | |
https://gist.github.com/marco79cgn/23ce08fd8711ee893a3be12d4543f2d2 | |
Retrieves the image from the local file store or downloads it once | |
*/ | |
async function getImage(image) { | |
let fm = FileManager.local() | |
let dir = fm.documentsDirectory() | |
let path = fm.joinPath(dir, image) | |
if (fm.fileExists(path)) { | |
return fm.readImage(path) | |
} else { | |
// download once | |
let imageUrl | |
switch (image) { | |
case 'temperature.png': | |
imageUrl = "https://<YOU NEED TO HOST THIS>/temperature.png" | |
break | |
case 'humidity.png': | |
imageUrl = "https://<YOU NEED TO HOST THIS>/humidity.png" | |
break | |
case 'hass-favicon.png': | |
imageUrl = "https://<HASS IP>/static/icons/favicon-192x192.png" | |
break | |
default: | |
console.log(`Sorry, couldn't find ${image}.`); | |
} | |
let iconImage = await loadImage(imageUrl) | |
fm.writeImage(path, iconImage) | |
return iconImage | |
} | |
} | |
/* | |
The following function is "borrowed" from: | |
https://gist.github.com/marco79cgn/23ce08fd8711ee893a3be12d4543f2d2 | |
Downloads an image from a given URL | |
*/ | |
async function loadImage(imgUrl) { | |
const req = new Request(imgUrl) | |
return await req.loadImage() | |
} | |
/* Searches for the respective sensor values ('state') in the API response of Home Assistant */ | |
function addData(json, room, sensors) { | |
room.temp = "N/A"; | |
room.humid = "N/A"; | |
var i; | |
for (i = 0; i < json.length; i++) { | |
if (json[i]['entity_id'] == sensors[0]) { | |
room.temp = Math.round(json[i]['state']); | |
} | |
if (json[i]['entity_id'] == sensors[1]) { | |
room.humid = Math.round(json[i]['state']); | |
} | |
} | |
return room; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment