Skip to content

Commit dee5018

Browse files
Create iqair clockinfo
make lint happier, standardize indentation
1 parent e91c350 commit dee5018

File tree

6 files changed

+236
-0
lines changed

6 files changed

+236
-0
lines changed

apps/airqualityci/ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0.01: Initial clockinfo release

apps/airqualityci/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Air Quality Clock Info
2+
3+
Create a list of clockinfos, each displaying air quality and/or temperature, fetched from IQAir
4+
5+
Requires Gadgetbridge internet access
6+
7+
# Display modes
8+
9+
Tapping the clockinfo changes its mode.
10+
11+
Examples of possible modes:
12+
- `45`
13+
- `45 31°`
14+
- `NYC 45`
15+
- `NYC 45 31°`
16+
- `NYC`
17+
18+
19+
Not affiliated with IQAir.

apps/airqualityci/app.png

1.63 KB
Loading

apps/airqualityci/clkinfo.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
(function() {
2+
let data = require("Storage").readJSON("airqualityci.json", 1) || {};
3+
let config = require("Storage").readJSON("airqualityci.settings.json") || {};
4+
5+
function checkAQI(cb) {
6+
let d = new Date();
7+
if (config.apiKey && config.rows && (data.aqiTime === undefined || data.aqiTime + 3600000 < d.getTime())) {
8+
data.aqi = [];
9+
config.rows.forEach((row) => {
10+
if (row.url) {
11+
let el = row.url.replace(/\/$/, "").split("/").reverse();
12+
let url = `https://api.airvisual.com/v2/city?city=${el[0]}&state=${el[1]}&country=${el[2]}&key=${config.apiKey}`;
13+
Bangle.http(url).then((r) => {
14+
let resp = JSON.parse(r.resp);
15+
data.aqiTime = d.getTime();
16+
data.aqi.push({
17+
url: row.url,
18+
aqius: resp.data.current.pollution.aqius,
19+
temp: resp.data.current.weather.tp
20+
});
21+
cb();
22+
require("Storage").writeJSON("airqualityci.json", data);
23+
});
24+
}
25+
});
26+
}
27+
}
28+
29+
let locs = {
30+
name: "AirQuality",
31+
items: []
32+
};
33+
34+
if (config.rows) {
35+
config.rows.forEach((row, id) => {
36+
locs.items.push({
37+
name: "AQI " + row.name,
38+
show: () => {},
39+
hide: () => {},
40+
run: function() {
41+
if ( ! config.rows[id].mode ) {
42+
config.rows[id].mode = 2;
43+
} else if ( config.rows[id].mode === 5 ){
44+
config.rows[id].mode = 1;
45+
} else {
46+
config.rows[id].mode += 1;
47+
}
48+
this.emit("redraw");
49+
require("Storage").writeJSON("airqualityci.settings.json", config);
50+
},
51+
get: function() {
52+
checkAQI(() => this.emit("redraw"));
53+
let aqi = data.aqi.find((e) => e.url == config.rows[id].url);
54+
let txt = "";
55+
switch ( config.rows[id].mode) {
56+
case 2:
57+
txt = ((aqi && aqi.aqius) || "...") + " " + ((aqi && aqi.temp) || "...") + "°";
58+
break;
59+
case 3:
60+
txt = row.name + " " + ((aqi && aqi.aqius) || "...");
61+
break;
62+
case 4:
63+
txt = row.name + " " + ((aqi && aqi.aqius) || "...") + " " + ((aqi && aqi.temp) || "...") + "°";
64+
break;
65+
case 5:
66+
txt = row.name;
67+
break;
68+
default:
69+
txt = ((aqi && aqi.aqius) || "...");
70+
}
71+
return {
72+
text: txt,
73+
short: ((aqi && aqi.aqius) || "..."),
74+
img: atob("GBiBAAA4AAB8AAd+AA++QB/d8D/t8D/p+DvqcBUPsA7vgB9fwA7vgAXvgAH/AAHwgAD3wAbfwA9/wA+/gA/fAA/OAA/gAAfAAAAAAA==")
75+
};
76+
}
77+
});
78+
});
79+
}
80+
81+
return locs;
82+
})

apps/airqualityci/custom.html

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<html>
2+
<head>
3+
<link rel="stylesheet" href="../../css/spectre.min.css">
4+
<style>
5+
input.offset {
6+
width: 80px;
7+
}
8+
input.name {
9+
width: 150px;
10+
}
11+
</style>
12+
</head>
13+
<body>
14+
<p>The AQI and temp are sourced from IQAir, which requires "Allow Internet Access" to be enabled in Gadgetbridge.</p>
15+
<p>To use AQI, you need an IQAir API key. To get one for free, create an IQAir account, then create an API key in <a target="_blank" href="https://dashboard.iqair.com/personal/api-keys">your user dashboard</a>.</p>
16+
<p>To specify the IQAir source, find your city on the IQAir website, then copy and paste the URL. It should look something like https://www.iqair.com/usa/new-york/new-york-city</p>
17+
<table id="rows" class="table table-scroll">
18+
<tr>
19+
<th>Name</th>
20+
<th>IQAir URL</th>
21+
</tr>
22+
</table>
23+
24+
<button id="addrow" class="btn">+</button>
25+
<button id="delrow" class="btn">-</button>
26+
<br>
27+
<input id="api-key" type="text" placeholder="IQAir API Key"></input>
28+
<br>
29+
<button id="upload" class="btn btn-primary">Upload</button>
30+
<template id="row-template">
31+
<tr class="row">
32+
<td>
33+
<input type="text" class="name"></input>
34+
</td>
35+
<td>
36+
<input type="text" class="url"></input>
37+
</td>
38+
</tr>
39+
</template>
40+
41+
<script src="../../core/lib/customize.js"></script>
42+
43+
<script>
44+
let storedString = localStorage.getItem('airqualityclockinfo-config');
45+
let stored = {};
46+
if (storedString) {
47+
stored = JSON.parse(storedString);
48+
}
49+
50+
if (stored.apiKey) {
51+
document.getElementById("api-key").value = stored.apiKey;
52+
}
53+
54+
if (!stored.rows) {
55+
stored.rows = [
56+
{
57+
name: "NYC",
58+
url: "https://www.iqair.com/usa/new-york/new-york",
59+
}
60+
];
61+
}
62+
63+
let tbl = document.getElementById("rows");
64+
let tmp = document.getElementById("row-template");
65+
for (let i = 0; i < stored.rows.length; i++) {
66+
let row = tmp.content.cloneNode(true);
67+
let storedRow = stored.rows[i]
68+
row.querySelector(".name").value = storedRow.name;
69+
row.querySelector(".url").value = storedRow.url;
70+
tbl.append(row);
71+
}
72+
73+
document.getElementById("addrow").addEventListener("click", function() {
74+
let tbl = document.getElementById("rows");
75+
let tmp = document.getElementById("row-template");
76+
let row = tmp.content.cloneNode(true);
77+
tbl.append(row);
78+
});
79+
80+
document.getElementById("delrow").addEventListener("click", function() {
81+
let tbl = document.getElementById("rows");
82+
tbl.deleteRow(tbl.rows.length -1);
83+
});
84+
85+
document.getElementById("upload").addEventListener("click", function() {
86+
let config = {
87+
rows: [],
88+
apiKey: document.getElementById("api-key").value
89+
};
90+
91+
document.querySelectorAll(".row").forEach((row) => {
92+
let name = row.querySelector(".name").value;
93+
let url = row.querySelector(".url").value;
94+
if ( name != "" && url != "" ) {
95+
config.rows.push({
96+
name: name,
97+
url: url,
98+
});
99+
}
100+
});
101+
102+
localStorage.setItem('airqualityclockinfo-config', JSON.stringify(config));
103+
104+
// send finished app (in addition to contents of app.json)
105+
sendCustomizedApp({
106+
storage:[
107+
{
108+
name: "airqualityci.settings.json",
109+
content: JSON.stringify(config)
110+
},
111+
]
112+
});
113+
});
114+
</script>
115+
</body>
116+
</html>

apps/airqualityci/metadata.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{ "id": "airqualityci",
2+
"name": "Air Quality Clockinfo",
3+
"version": "0.01",
4+
"description": "Create clockinfos for air quality and temperature",
5+
"icon": "app.png",
6+
"type": "clkinfo",
7+
"tags": "clkinfo",
8+
"supports" : ["BANGLEJS2"],
9+
"readme": "README.md",
10+
"custom": "custom.html",
11+
"storage": [
12+
{"name":"airqualityci.clkinfo.js","url":"clkinfo.js"}
13+
],
14+
"data": [
15+
{"name":"airqualityci.json"},
16+
{"name":"airqualityci.settings.json"}
17+
]
18+
}

0 commit comments

Comments
 (0)