local composer = require( "composer" ) local json = require("json") local widget = require("widget") local AskiRepository = require("askirepository") local scene = composer.newScene() -- Globale Variablen für Datenabruf local yesterdayDate = nil local selectedDate = nil -- ----------------------------------------------------------------------------------- -- Code outside of the scene event functions below will only be executed ONCE unless -- the scene is removed entirely (not recycled) via "composer.removeScene()" -- ----------------------------------------------------------------------------------- -- Hilfsfunktion: Hole Datum minus 7 Tage Datum local function getCurrentAndLastDate(isCurrentDate) local currentTime = os.time() --print("Aktuelle Zeit (Timestamp): " .. currentTime) local lastSevenDayTime = currentTime - (24 * 60 * 60 * 7) -- 7 Tage zurück --print("Vor 7 Tagen Zeit (Timestamp): " .. lastSevenDayTime) if isCurrentDate then return os.date("*t", currentTime - (24 * 60 * 60)) -- minus 1 Tag für gestern else return os.date("*t", lastSevenDayTime - (24 * 60 * 60)) -- nochmal minus 1 Tag für vor 7 Tage end end -- Hilfsfunktion: Formatiere Datum für API local function formatDateForAPI(dateTable, isEndOfDay) if isEndOfDay then return string.format("%04d-%02d-%02dT23:59:59.999Z", dateTable.year, dateTable.month, dateTable.day) else return string.format("%04d-%02d-%02dT00:00:00.000Z", dateTable.year, dateTable.month, dateTable.day) end end -- Go to Day scene02 local function gotoDay() composer.gotoScene("scenen.scene01", { effect = "fade", time = 500 }) end -- ----------------------------------------------------------------------------------- -- Scene event functions -- ----------------------------------------------------------------------------------- -- create() function scene:create( event ) local sceneGroup = self.view -- Code here runs when the scene is first created but has not yet appeared on screen -- Hintergrund local bg = display.newRect(sceneGroup, display.contentCenterX, display.contentCenterY, display.contentWidth, display.contentHeight) bg:setFillColor(0.95, 0.95, 0.95) -- aktuelles Tagesdatum -1 Tag für gestern yesterdayDate = getCurrentAndLastDate(true) -- Setze Standard-Datum auf vor 8 Tagen selectedDate = getCurrentAndLastDate(false) end -- show() function scene:show( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Code here runs when the scene is still off screen (but is about to come on screen) elseif ( phase == "did" ) then -- Hole die übergebenen Daten local devices = event.params.devices local currentCookie = event.params.cookie -- Formatiere die Daten für die API local fromDate = formatDateForAPI(selectedDate, false) local toDate = formatDateForAPI(yesterdayDate, true) local completedRequests = 0 local totalRequests = #devices local currentDataSets = {} -- Ausgabe der übergebenen Daten für Debugging print("Scene02 ist jetzt sichtbar - Zeige Daten an") print("Entspricht einer Woche von Gestern 7 Tage zurück") print("Formatiertes Start-Datum für API: " .. fromDate) print("Formatiertes End-Datum für API: " .. toDate) print("Übergebene Geräte: " .. (devices and #devices or "Keine")) print("Cookie:" .. tostring(currentCookie)) -- Funktion zur Anzeige des Balkendiagramms local function displayBarChart(dataSets) -- Entferne alte Diagramm-Anzeigen for i = sceneGroup.numChildren, 1, -1 do local child = sceneGroup[i] if child._isChartDisplay then child:removeSelf() end end if not dataSets or type(dataSets) ~= "table" then print("Keine Daten zum Anzeigen") return end -- Definiere Farben für die Devices local deviceColors = { ["Traun"] = {0.2, 0.4, 0.9}, -- Blau ["Lannach"] = {0.3, 0.8, 0.4}, -- Grün ["Sarleinsbach"] = {0.95, 0.6, 0.2} -- Orange } -- Parameter für das Diagramm local chartX = display.contentCenterX local chartY = 150 local chartWidth = display.contentWidth - 40 local chartHeight = 180 -- Hintergrund für das Diagramm local chartBg = display.newRoundedRect(sceneGroup, chartX, chartY, chartWidth, chartHeight, 8) chartBg:setFillColor(1, 1, 1) chartBg.strokeWidth = 2 chartBg:setStrokeColor(0.7, 0.7, 0.7) chartBg._isChartDisplay = true -- Titel local titleText = display.newText({ parent = sceneGroup, text = "Wochenübersicht (kW)", x = chartX, y = chartY - chartHeight/2 - 15, fontSize = 16, font = native.systemFontBold }) titleText:setFillColor(0.2, 0.2, 0.2) titleText._isChartDisplay = true -- Organisiere Daten nach Tag local dayData = {} -- { ["2024-05-20"] = { Traun = value, Lannach = value, Sarleinsbach = value } } local maxValue = 0 for deviceName, dataSet in pairs(dataSets) do if not dataSet.error and type(dataSet) == "table" and #dataSet > 0 then for _, meter in ipairs(dataSet) do if meter.values and #meter.values > 0 then for _, valueData in ipairs(meter.values) do if valueData.value and valueData.datetime then local date = valueData.datetime:match("(%d%d%d%d%-%d%d%-%d%d)") if date then if not dayData[date] then dayData[date] = {} end dayData[date][deviceName] = valueData.value maxValue = math.max(maxValue, valueData.value) end end end break -- Nur das erste Meter pro Device end end end end -- Sortiere Tage local sortedDays = {} for day in pairs(dayData) do table.insert(sortedDays, day) end table.sort(sortedDays) if #sortedDays == 0 then local noDataText = display.newText({ parent = sceneGroup, text = "Keine Daten zum Anzeigen", x = chartX, y = chartY, fontSize = 14 }) noDataText:setFillColor(0.5, 0.5, 0.5) noDataText._isChartDisplay = true return end -- Berechne Diagramm-Parameter local graphLeft = chartX - chartWidth/2 + 30 local graphRight = chartX + chartWidth/2 - 10 local graphTop = chartY - chartHeight/2 + 25 local graphBottom = chartY + chartHeight/2 - 35 local graphWidth = graphRight - graphLeft local graphHeight = graphBottom - graphTop -- Zeichne Y-Achse local yAxis = display.newLine(sceneGroup, graphLeft, graphTop, graphLeft, graphBottom) yAxis:setStrokeColor(0.5, 0.5, 0.5) yAxis.strokeWidth = 2 yAxis._isChartDisplay = true -- Zeichne X-Achse local xAxis = display.newLine(sceneGroup, graphLeft, graphBottom, graphRight, graphBottom) xAxis:setStrokeColor(0.5, 0.5, 0.5) xAxis.strokeWidth = 2 xAxis._isChartDisplay = true -- Y-Achsen-Beschriftung local maxLabel = display.newText({ parent = sceneGroup, text = string.format("%.0f", maxValue), x = graphLeft - 15, y = graphTop, fontSize = 9 }) maxLabel:setFillColor(0.4, 0.4, 0.4) maxLabel._isChartDisplay = true local zeroLabel = display.newText({ parent = sceneGroup, text = "0", x = graphLeft - 15, y = graphBottom, fontSize = 9 }) zeroLabel:setFillColor(0.4, 0.4, 0.4) zeroLabel._isChartDisplay = true -- Zeichne Balken für jeden Tag local dayWidth = graphWidth / #sortedDays local barSpacing = 4 local barWidth = dayWidth - barSpacing * 2 for i, day in ipairs(sortedDays) do local dayX = graphLeft + (i - 0.5) * dayWidth local data = dayData[day] -- Datum-Label local dayLabel = display.newText({ parent = sceneGroup, text = day:match("%d%d%-%d%d$"), -- Nur MM-DD x = dayX, y = graphBottom + 12, fontSize = 8 }) dayLabel:setFillColor(0.3, 0.3, 0.3) dayLabel._isChartDisplay = true -- Berechne Gesamtwert für diesen Tag local totalValue = 0 local deviceOrder = {"Traun", "Lannach", "Sarleinsbach"} for _, deviceName in ipairs(deviceOrder) do totalValue = totalValue + (data[deviceName] or 0) end if totalValue > 0 then -- Zeichne gestapelten Balken - prozentual zur vollen Diagrammhöhe local currentY = graphBottom for _, deviceName in ipairs(deviceOrder) do local value = data[deviceName] or 0 if value > 0 then -- Berechne Segment-Höhe proportional zum Anteil am Gesamtwert -- Balken nutzt die volle Höhe, Segmente sind prozentual local percentage = value / totalValue local segmentHeight = percentage * graphHeight local segmentY = currentY - segmentHeight/2 -- Segment local segment = display.newRect(sceneGroup, dayX, segmentY, barWidth, segmentHeight) local color = deviceColors[deviceName] or {0.5, 0.5, 0.5} segment:setFillColor(unpack(color)) segment.strokeWidth = 1 segment:setStrokeColor(0.9, 0.9, 0.9) segment._isChartDisplay = true -- Wert-Label im Segment (wenn genug Platz) if segmentHeight > 12 then local valueLabel = display.newText({ parent = sceneGroup, text = string.format("%d\n%.0f%%", value, percentage * 100), x = dayX, y = segmentY, fontSize = 7, font = native.systemFontBold }) valueLabel:setFillColor(1, 1, 1) valueLabel._isChartDisplay = true end -- Bewege Y-Position nach oben für nächstes Segment currentY = currentY - segmentHeight end end -- Gesamtwert über dem Balken local totalLabel = display.newText({ parent = sceneGroup, text = string.format("%d", totalValue), x = dayX, y = graphTop - 8, fontSize = 8, font = native.systemFontBold }) totalLabel:setFillColor(0.2, 0.2, 0.2) totalLabel._isChartDisplay = true end end -- Legende local legendY = chartY + chartHeight/2 + 20 local legendDevices = { {name = "Traun", color = deviceColors["Traun"]}, {name = "Lannach", color = deviceColors["Lannach"]}, {name = "Sarleinsbach", color = deviceColors["Sarleinsbach"]} } for i, legend in ipairs(legendDevices) do local legendX = chartX - 90 + ((i - 1) * 90) -- Farbbox local colorBox = display.newRect(sceneGroup, legendX - 20, legendY, 12, 8) colorBox:setFillColor(unpack(legend.color)) colorBox._isChartDisplay = true -- Device Name local legendText = display.newText({ parent = sceneGroup, text = legend.name, x = legendX + 10, y = legendY, fontSize = 10 }) legendText:setFillColor(0.3, 0.3, 0.3) legendText._isChartDisplay = true end print("✓ Balkendiagramm erstellt für " .. #sortedDays .. " Tage") end -- Funktion zum Neuladen der Daten local function reloadDataFromSevenDays() if not currentCookie or not devices or not selectedDate then print("Fehler: Cookie, Devices oder Datum fehlt") return end print("Lade Daten von " .. string.format("%04d-%02d-%02d", selectedDate.year, selectedDate.month, selectedDate.day) .. " bis " .. string.format("%04d-%02d-%02d", yesterdayDate.year, yesterdayDate.month, yesterdayDate.day) .. " für " .. #devices .. " Geräte") -- Lade-Anzeige local loadingOverlay = display.newRect(sceneGroup, display.contentCenterX, display.contentCenterY, display.contentWidth, display.contentHeight) loadingOverlay:setFillColor(0, 0, 0, 0.5) loadingOverlay._isDataDisplay = true local loadingText = display.newText({ parent = sceneGroup, text = "Lade Daten...", x = display.contentCenterX, y = display.contentCenterY, fontSize = 20, font = native.systemFontBold }) loadingText:setFillColor(1, 1, 1) loadingText._isDataDisplay = true -- Callback für jeden Device local function onDataComplete(deviceName, success, dataSet, response) completedRequests = completedRequests + 1 if success then currentDataSets[deviceName] = dataSet else currentDataSets[deviceName] = { error = tostring(response) } end if completedRequests >= totalRequests then -- Entferne Lade-Anzeige loadingOverlay:removeSelf() loadingText:removeSelf() -- Ausgabe der kompletten newDeviceDataSets Table print("\n========== ALLE GELADENEN DATEN (newDeviceDataSets) ==========") print("JSON-Format:") print(json.prettify(currentDataSets)) print("===============================================================\n") -- Zeige neue Daten print("✓ Daten erfolgreich geladen") -- Zeige Balkendiagramm displayBarChart(currentDataSets) end end -- Lade Daten für alle Devices for i, device in ipairs(devices) do local function deviceCallback(success, dataSet, response) onDataComplete(device.name, success, dataSet, response) end AskiRepository.getPostHistoricData( "https://api.portal.aski.at/historical_values/power", device.deviceId, fromDate, toDate, currentCookie, deviceCallback ) end end -- Code here runs when the scene is entirely on screen reloadDataFromSevenDays() -- Lade die Daten direkt beim Anzeigen der Scene02 -- Inhalt Diagramm anzeigen -- Button für zurück zu Scene01 -- Design für Tagesansicht Button local dayBtn = widget.newButton({ label = "Vortagesansicht", emboss = false, shape = "roundedRect", width = 200, height = 40, cornerRadius = 8, fillColor = { default = { 0.3, 0.5, 0.8, 1 }, over = { 0.2, 0.4, 0.7, 1 } }, strokeColor = { default = { 0.2, 0.4, 0.2, 1 }, over = { 0.1, 0.3, 0.1, 1 } }, strokeWidth = 2, labelColor = { default = { 1, 1, 1 }, over = { 1, 1, 1 } }, fontSize = 16, x = display.contentCenterX, y = 380 }) -- Event-Listener für Tagesansicht Button sceneGroup:insert(dayBtn) dayBtn:addEventListener("tap", gotoDay) end end -- hide() function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Code here runs when the scene is on screen (but is about to go off screen) elseif ( phase == "did" ) then -- Code here runs immediately after the scene goes entirely off screen end end -- destroy() function scene:destroy( event ) local sceneGroup = self.view -- Code here runs prior to the removal of scene's view print("Scene02 zerstört") end -- ----------------------------------------------------------------------------------- -- Scene event function listeners -- ----------------------------------------------------------------------------------- scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) -- ----------------------------------------------------------------------------------- return scene