• hiking_silhouette.jpg
  • robert_scouting.jpg
  • homey.jpg
  • route.jpg
  • compass-1130x200.elsinga.net.jpg
  • dashcam.jpg

Op de Ulanzi TC002 met Awtrix NG 1.2.2 firmware hebben we een mooi 52x16 resolutie tot onze beschikking voor het tonen van een grafiek met de komende dynamische energieprijzen:

energiegrafiek

Hier is een energiegrafiek te zien die om 12:00 op de TC002 is getoond. Omdat er 13 uren aan prijzen getoond kunnen worden en de prijzen voor morgen nog niet bekend zijn, worden de voorspelde prijzen gedimd rechts getoond.

Dit scherm wordt geregeld met 2 scripts: een Homeyscript dat al het rekenwerk doet en eventueel voorspelde prijzen ophaalt en een Berry script op de TC002 dat daadwerkelijk de grafiek toont. Dat is nodig omdat de TC002 met Awtrix NG firmware 1.2.2 (geheel onnodig in dit geval) alles wat via de API schaalt naar 8 pixels hoog. Door alleen de data van de kolommen naar de API te sturen en de TC002 dit zelf te laten tekenen wordt dit voorkomen.

Hieronder de flow die dit regelt:

Homey flow energiegrafiek

De prijzen worden via Power by the Hour elk kwartier opgehaald en in tekst variabelen gezet (omdat ze anders niet van elkaar zijn te onderscheiden in de flowkaarten die volgen). Deze variabelen worden in het Homeyscript in de volgende flow kaart gestopt en die levert de payload voor het Berry script op de TC002 op. Dit werkt niet bij een regulier Homeyscript, omdat er geen flow kaart bestaat die een Homeyscript aanroept en het resultaat teruglevert in de flow. 

Omdat Power by the Hour de prijzen voor morgen niet automatisch leeg maakt resetten we die rond middernacht:

Homey Flow reset PbtH morgen

Benodigde variabelen:

  • (a) Grafiek_PbtH_Vandaag
  • (a) Grafiek_PbtH_Morgen

Het Homeyscript in de flow kaart ziet er als volgt uit:

// ============================================================================
// Homeyscript: Awtrix NG Energiegrafiek Payload Generator (Automatische Interval)
// ============================================================================

const logicVars = await Homey.logic.getVariables();
let todayStr = "";
let tomorrowStr = "";

// 1. Haal de PBTH variabelen op uit Homey Logic
for (let id in logicVars) {
let name = logicVars[id].name.toLowerCase();
if (name === "grafiek_pbth_vandaag") todayStr = logicVars[id].value;
if (name === "grafiek_pbth_morgen") tomorrowStr = logicVars[id].value;
}

function parsePrices(str) {
if (!str) return [];
return str.replace(/[\[\]\s]/g, '').split(',').map(p => parseFloat(p)).filter(p => !isNaN(p));
}

let todayPrices = parsePrices(todayStr);
let tomorrowPrices = parsePrices(tomorrowStr);
let allPrices = todayPrices.concat(tomorrowPrices);

if (allPrices.length === 0) {
return JSON.stringify({"energieData": []});
}

// 2. Bepaal automatisch het huidige index-type (Uur vs. Kwartier)
const nowUtc = new Date();
const now = new Date(nowUtc.toLocaleString("en-US", {timeZone: "Europe/Amsterdam"}));

let currentIndex = 0;
if (todayPrices.length <= 24) {
// Uurprijzen (24 waardes per dag)
currentIndex = now.getHours();
} else {
// Kwartierprijzen (96 waardes per dag)
currentIndex = (now.getHours() * 4) + Math.floor(now.getMinutes() / 15);
}

// 3. Venster bepalen: 52 kolommen totaal (4 staven historie + 48 staven toekomst)
let startIndex = Math.max(0, currentIndex - 4);
let slicePrices = allPrices.slice(startIndex, startIndex + 52);

// Bepaal min en max voor dynamische schaaling binnen het zichtbare venster
let minPrice = Math.min(...slicePrices);
let maxPrice = Math.max(...slicePrices);
if (minPrice === maxPrice) { minPrice -= 0.05; maxPrice += 0.05; }

// 4. Absoluut kleurenschema
function getColor(price) {
if (price > 0.45) return 0xFF0000; // Rood (> 45 ct)
if (price > 0.35) return 0xFFAA00; // Oranje (35 - 45 ct)
if (price >= 0.25) return 0xFFFF00; // Geel (25 - 35 ct)
if (price >= 0.132) return 0x00FF00; // Groen (13.2 - 25 ct)
if (price < 0) return 0x9900FF; // Paars (negatieve prijs)
return 0x00FF00;
}

// 5. Bouw de payload array op voor Awtrix
let payload = [];

for (let i = 0; i < slicePrices.length; i++) {
let price = slicePrices[i];
let globalIndex = startIndex + i;

let normalized = (price - minPrice) / (maxPrice - minPrice);
let barHeight = Math.max(1, Math.round(normalized * 13));

let y0 = 15;
let y1 = 15 - barHeight;

let isCurrent = (globalIndex === currentIndex);
let isFuture = (globalIndex > currentIndex);

payload.push({
"y0": y0,
"y1": y1,
"c": getColor(price),
"tm": isCurrent ? 1 : 0, // Witte stip boven het huidige uur
"f": isFuture ? 1 : 0 // Dimt de voorspelde uren
});
}

return JSON.stringify({"energieData": payload});

Het Berry script op de TC002 heet "energiegrafiek" en ziet er als volgt uit:

class EnergieGrafiek
# Hulpfunctie om een kleur te dimmen naar ~35% helderheid
def dimColor(c)
var r = int(((c >> 16) & 0xFF) * 0.35)
var g = int(((c >> 8) & 0xFF) * 0.35)
var b = int((c & 0xFF) * 0.35)

return (r << 16) | (g << 8) | b
end

def draw()
var data = store.get("energieData")

if data == nil return end
if type(data) != "list" && type(data) != "instance" return end
if size(data) == 0 return end

for x: 0 .. size(data)-1
if x > 51 break end

var colData = data[x]

var y0 = int(colData["y0"])
var y1 = int(colData["y1"])
var col = int(colData["c"])
var tm = int(colData["tm"])

# Als Homey 'f': 1 meegeeft voor voorspelde prijzen, dimmen we de kleur
if colData.contains("f") && int(colData["f"]) == 1
col = self.dimColor(col)
end

line(x, y0, x, y1, col)

# Tijd-marker (wit stipje bovenin)
if tm == 1
pixel(x, 0, 0xFFFFFF)
end
end
end
end
return EnergieGrafiek()