fbf40f75b2
- petrol watch - copilot usage Signed-off-by: Peter Siegmund <developer@mars3142.org>
152 lines
4.3 KiB
JavaScript
152 lines
4.3 KiB
JavaScript
class PetrolAction {
|
|
constructor($UD, context) {
|
|
this.$UD = $UD;
|
|
this.context = context;
|
|
this.config = {
|
|
url: '',
|
|
stationUuid: '',
|
|
fuelType: '',
|
|
refreshRate: '1',
|
|
};
|
|
this.refreshTimer = null;
|
|
this.debounceTimer = 0;
|
|
this.previousPrice = null;
|
|
this.lastDelta = null;
|
|
|
|
this.$UD.onDidReceiveSettings(jsn => {
|
|
if (jsn.context !== this.context) return;
|
|
const s = jsn.settings || {};
|
|
this.config = Object.assign(this.config, s);
|
|
if (s.previousPrice != null) this.previousPrice = s.previousPrice;
|
|
if (s.lastDelta != null) this.lastDelta = s.lastDelta;
|
|
});
|
|
}
|
|
|
|
setActive() {}
|
|
|
|
onClear() {
|
|
if (this.refreshTimer) {
|
|
clearInterval(this.refreshTimer);
|
|
this.refreshTimer = null;
|
|
}
|
|
if (this.debounceTimer) {
|
|
clearTimeout(this.debounceTimer);
|
|
this.debounceTimer = 0;
|
|
}
|
|
}
|
|
|
|
setParams(jsn) {
|
|
const params = (jsn && jsn.param) || {};
|
|
this.config = Object.assign(this.config, params);
|
|
this.$UD.getSettings(this.context);
|
|
this.start();
|
|
}
|
|
|
|
onRun() {
|
|
this.fetchPrice();
|
|
}
|
|
|
|
start() {
|
|
this.onClear();
|
|
this.fetchPrice();
|
|
const duration = this.getRefreshDuration();
|
|
if (duration > 0) {
|
|
this.refreshTimer = setInterval(() => this.fetchPrice(), duration * 60 * 1000);
|
|
}
|
|
}
|
|
|
|
async fetchPrice() {
|
|
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
this.debounceTimer = setTimeout(async () => {
|
|
if (!this.config.url || !this.config.stationUuid || !this.config.fuelType) {
|
|
this.renderButton('?', null);
|
|
return;
|
|
}
|
|
try {
|
|
const response = await fetch(this.config.url);
|
|
const text = await response.text();
|
|
const raw = this.parsePrometheus(text);
|
|
if (raw) {
|
|
const current = parseFloat(raw);
|
|
if (this.previousPrice !== null) {
|
|
const delta = current - this.previousPrice;
|
|
if (delta !== 0) this.lastDelta = delta;
|
|
}
|
|
this.previousPrice = current;
|
|
this.renderButton(`${raw}€`, this.lastDelta);
|
|
this.$UD.setSettings({ ...this.config, previousPrice: this.previousPrice, lastDelta: this.lastDelta }, this.context);
|
|
} else {
|
|
this.renderButton('N/A', null);
|
|
}
|
|
} catch (e) {
|
|
this.renderButton('ERR', null);
|
|
}
|
|
}, 300);
|
|
}
|
|
|
|
parsePrometheus(text) {
|
|
for (const line of text.split('\n')) {
|
|
const trimmed = line.trim();
|
|
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
if (trimmed.startsWith('petrol_price_euro') && trimmed.includes(this.config.stationUuid) && trimmed.includes(this.config.fuelType)) {
|
|
const closingBrace = trimmed.indexOf('}');
|
|
if (closingBrace !== -1) return trimmed.slice(closingBrace + 1).trim();
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
renderButton(priceText, delta) {
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = 196;
|
|
canvas.height = 196;
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
ctx.fillStyle = '#000000';
|
|
ctx.fillRect(0, 0, 196, 196);
|
|
|
|
ctx.strokeStyle = '#000';
|
|
ctx.lineWidth = 3;
|
|
ctx.textBaseline = 'middle';
|
|
ctx.textAlign = 'center';
|
|
|
|
// Fuel type — top, light blue
|
|
ctx.fillStyle = '#7ec8e3';
|
|
ctx.font = 'bold 28px "Source Han Sans SC"';
|
|
ctx.strokeText(this.config.fuelType, 98, 45);
|
|
ctx.fillText(this.config.fuelType, 98, 45);
|
|
|
|
// Price — middle, yellow
|
|
const fSize = priceText.length > 6 ? 34 - priceText.length : 40;
|
|
ctx.fillStyle = '#f0c040';
|
|
ctx.font = `bold ${fSize}px "Source Han Sans SC"`;
|
|
ctx.strokeText(priceText, 98, 105);
|
|
ctx.fillText(priceText, 98, 105);
|
|
|
|
// Delta — bottom
|
|
if (delta !== null) {
|
|
const arrow = delta > 0 ? '▲' : '▼';
|
|
const color = delta > 0 ? '#ff6b6b' : '#6bff6b';
|
|
const deltaText = `${arrow} ${Math.abs(delta).toFixed(3)}`;
|
|
ctx.fillStyle = color;
|
|
ctx.font = '18px "Source Han Sans SC"';
|
|
ctx.strokeText(deltaText, 98, 142);
|
|
ctx.fillText(deltaText, 98, 142);
|
|
}
|
|
|
|
this.$UD.setBaseDataIcon(this.context, canvas.toDataURL('image/png'));
|
|
}
|
|
|
|
getRefreshDuration() {
|
|
switch (this.config.refreshRate) {
|
|
case '1': return 1;
|
|
case '2': return 2;
|
|
case '3': return 5;
|
|
case '4': return 10;
|
|
case '5': return 30;
|
|
case '6': return 60;
|
|
default: return 0;
|
|
}
|
|
}
|
|
}
|