Skip to content

Instantly share code, notes, and snippets.

@Critter
Forked from jasonsnell/purpleaqijsnell.js
Created August 27, 2020 03:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Critter/75abec5470b97bfc8098573030afd0c8 to your computer and use it in GitHub Desktop.
Save Critter/75abec5470b97bfc8098573030afd0c8 to your computer and use it in GitHub Desktop.
Purple AQI Widget
const API_URL = "https://www.purpleair.com/json?show=";
// const CACHE_FILE = "aqi_data.json"
// Find a nearby PurpleAir sensor ID via https://fire.airnow.gov/
// Click a sensor near your location: the ID is the trailing integers
// https://www.purpleair.com/json has all sensors by location & ID.
let SENSOR_ID = args.widgetParameter || "4896"
async function getSensorData(url, id) {
let req = new Request(`${url}${id}`)
let json = await req.loadJSON()
return {
"val": json.results[0].PM2_5Value,
"ts": json.results[0].LastSeen,
"loc": json.results[0].Label
}
}
// Calculates the AQI level based on
// https://cfpub.epa.gov/airnow/index.cfm?action=aqibasics.aqi#unh
function calculateLevel(aqi) {
let res = {
level: "OK",
color: Color.white()
}
let level = parseInt(aqi, 10) || 0
if (level > 300) {
res.level = "Hazardous"
res.color = new Color('7e0023')
return res
} else if (level > 200) {
res.level = "Very Unhealthy"
res.color = new Color('8f3f97')
return res
} else if (level > 151) {
res.level = "Unhealthy"
res.color = Color.red()
return res
} else if (level > 101) {
res.level = "Unhealthy (S.G.)"
res.color = new Color('ff7e00')
return res
} else if (level > 51) {
res.level = "Moderate"
res.color = new Color('ffff00')
return res
} else if (level > 0) {
res.level = "Good"
res.color = new Color('00e400')
return res
}
return res
}
//Function to get AQI number from PPM reading
function aqiFromPM (pm) {
if (pm > 350.5) {
return calcAQI(pm, 500.0, 401.0, 500.0, 350.5)
} else if (pm > 250.5) {
return calcAQI(pm, 400.0, 301.0, 350.4, 250.5)
} else if (pm > 150.5) {
return calcAQI(pm, 300.0, 201.0, 250.4, 150.5)
} else if (pm > 55.5) {
return calcAQI(pm, 200.0, 151.0, 150.4, 55.5)
} else if (pm > 35.5) {
return calcAQI(pm, 150.0, 101.0, 55.4, 35.5)
} else if (pm > 12.1) {
return calcAQI(pm, 100.0, 51.0, 35.4, 12.1)
} else if (pm >= 0.0) {
return calcAQI(pm, 50.0, 0.0, 12.0, 0.0)
} else {
return "-"
}
}
//Function that actually calculates the AQI number
function calcAQI(Cp, Ih, Il, BPh, BPl) {
let a = (Ih - Il);
let b = (BPh - BPl);
let c = (Cp - BPl);
return Math.round((a/b) * c + Il);
}
async function run() {
let wg = new ListWidget()
try {
console.log(`Using sensor ID: ${SENSOR_ID}`)
let data = await getSensorData(API_URL, SENSOR_ID)
console.log(data)
let header = wg.addText("Air Quality")
header.textSize = 15
header.textColor = Color.black()
let aqi = aqiFromPM(data.val)
let level = calculateLevel(aqi)
let aqitext = aqi.toString()
console.log(aqi)
console.log(level.level)
wg.backgroundColor = level.color
let content = wg.addText(aqitext)
content.textSize = 50
content.textColor = Color.black()
let wordLevel = wg.addText(level.level)
wordLevel.textSize = 15
wordLevel.textColor = Color.black()
let id = wg.addText(data.loc)
id.textSize = 10
id.textColor = Color.black()
let updatedAt = new Date(data.ts*1000).toLocaleTimeString("en-US", { timeZone: "PST" })
let ts = wg.addText(`Updated ${updatedAt}`)
ts.textSize = 10
ts.textColor = Color.black()
} catch (e) {
console.log(e)
let err = wg.addText(`error: ${e}`)
err.textSize = 10
err.textColor = Color.red()
err.textOpacity = 30
}
Script.setWidget(wg)
Script.complete()
}
await run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment