Balkonkraftwerke von Lidl, Netto, ALDI und Kaufland im Test

Einleitung:

In einem aktuellen YouTube-Video hat Andreas Schmitz (@akkudoktor@Twitter.com) zusammen mit Professor Krauter von der Uni Paderborn die Balkonkraftwerke von Lidl und Netto einem Test unterzogen. Die Ergebnisse waren besorgniserregend, insbesondere in Bezug auf die Zuverlässigkeit und die Angaben der Hersteller. In diesem Blogbeitrag werden wir die Ergebnisse des Tests sachlich und technisch versiert betrachten.

“Der Fachwerker” hat in seinem YouTube Video die Balkonkraftwerke von Aldi und Kaufland getestet. Das Video ist unter der Rubrik Kaufland zu finden.

Weiterlesen
Veröffentlicht unter Blogroll, Solar | Verschlagwortet mit , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Schreib einen Kommentar

Proxmox Host: SSD-Tausch, Datenmigration und USB-Speicher Integration

In diesem Blogpost möchte ich meine Erfahrungen beim Tausch einer SSD in meinem Proxmox Host teilen, die verschiedenen Herausforderungen, die ich dabei hatte, sowie eine Anleitung zur Integration eines USB-Speichers in Proxmox.

Mein Proxmox Host ist ein Intel NUC mit einer 1TB NVMe und einer zusätzlichen Crucial BX500 SSD. Kürzlich stellte ich fest, dass eine meiner Windows-VMs sehr langsam geworden ist, obwohl die Speicherauslastung und CPU-Auslastung nicht übermäßig hoch waren. Bei der Überprüfung der S.M.A.R.T. Werte stieß ich auf einen Wearout von 40%. Die SSD war mit 750GB bei einer Größe von 1TB bereits überlastet.

Weiterlesen
Veröffentlicht unter Blogroll | Verschlagwortet mit , , , , , , , , , , , , , , , , , , | Schreib einen Kommentar

Sentry.io – Ein umfassendes Tool für effiziente Fehlerüberwachung, -behebung und Leistungsüberwachung in Ihrer Anwendung

Entwickler kennen die Herausforderungen, die mit der Fehlerbehebung und Leistungsüberwachung von Softwareprojekten einhergehen. Ein effizientes Tool zur Überwachung und Behebung dieser Probleme ist entscheidend, um die Qualität und Zuverlässigkeit Ihrer Anwendung sicherzustellen. In diesem Blog-Post stellen wir Ihnen Sentry.io vor, ein umfassendes Tool, das Entwicklern hilft, Fehler zu überwachen, zu beheben und die Leistung ihrer Anwendungen zu optimieren.

Was ist Sentry.io?

Sentry.io ist eine leistungsstarke Fehlerüberwachungs- und Leistungsüberwachungsplattform, die Entwicklern hilft, Fehler in Echtzeit zu erkennen und zu beheben. Es bietet eine Vielzahl von Funktionen und Integrationen, die die Zusammenarbeit und den Entwicklungsprozess vereinfachen und beschleunigen.

Weiterlesen
Veröffentlicht unter C#, Nützliches, Programmierung | Verschlagwortet mit , , , , , , , , , , , , , , , , , , , , , , , , | Schreib einen Kommentar

Rekursive SQL-Abfragen: Die Macht der Hierarchien meistern

In der Welt der relationalen Datenbanken gibt es oft Situationen, in denen Daten in einer hierarchischen Struktur organisiert sind. Das kann von einfachen Kategorien und Unterkategorien bis hin zu komplexen Organisationsstrukturen reichen. Um solche Hierarchien effektiv abzufragen, benötigen wir rekursive SQL-Abfragen. In diesem Blogbeitrag werden wir uns mit rekursiven SQL-Abfragen in SQL Server, MySQL und PostgreSQL befassen. Ob Sie ein Datenbankprofi oder ein technikbegeisterter Anfänger sind, dieser Beitrag wird Ihnen helfen, die Grundlagen der rekursiven SQL-Abfragen zu verstehen.

Rekursive SQL-Abfragen in SQL Server:

In SQL Server können wir rekursive Abfragen mit der Common Table Expression (CTE) erstellen. Eine CTE ist eine temporäre Ergebnismenge, die innerhalb des Geltungsbereichs einer einzelnen SELECT-, INSERT-, UPDATE-, DELETE- oder CREATE VIEW-Anweisung definiert ist. Um eine rekursive CTE zu erstellen, verwenden wir die UNION ALL-Anweisung, um die Basis- und Rekursionsfälle zu verbinden. Im vorherigen Beispiel haben wir eine rekursive CTE verwendet, um eine Hierarchie von Organisationsstrukturen zu durchlaufen und ihre jeweilige Ebene abzurufen.

Weiterlesen
Veröffentlicht unter MsSQL Server, SQL | Verschlagwortet mit , , , , , , , , , , , , , , | Schreib einen Kommentar

Netatmo Security Cam Stream in ioBroker VIS anzeigen

Einleitung

Die Netatmo Security Kamera ist ein beliebtes Sicherheitsprodukt, das viele Anwender aufgrund seiner einfachen Bedienbarkeit und hervorragenden Leistung schätzen. In letzter Zeit hat sich jedoch eine Änderung abgezeichnet: Netatmo wird demnächst nicht mehr über den statischen Schlüssel lokal erreichbar sein. Zum anzeigen des aktuellen Bildes muss man nun auf die URL zurückgreifen die die API liefert – das ist einfacher 😉

In diesem Blog-Beitrag werden wir uns anschauen, wie wir die dynamische URL vom Adapter nutzen können, um die Netatmo Security Kamera in die VIS-Oberfläche des ioBrokers einzubinden.
Da das m3u8-Format nicht direkt abspielbar ist, zeige ich eine Lösung mittels Node Red und iFrame in VIS in Kombination mit dem HLS.js Framework. Zusätzlich erläutere ich die Verwendung von HLS.js und die Umsetzung ohne HTTPS.
‼️ Zur Anzeige nutze ich Fully Kiosk Browser auf einem Lenovo Tab M10, Android version 10 (SDK 29), Webview version 112.0.5615.101

Für diejenigen, die ihre VIS und Kamera per HTTPS erreichen möchten, empfehlen ich die Nutzung eines HTTPS-Reverse-Proxy wie Traefik. Man muss nur die Daten noch so umschreiben, dass sie nicht von der lokalen Kamera kommen, sondern über den Reverse Proxy 🙂 siehe Schritt 5

HLS.js: Ein kurzer Überblick

HLS.js ist eine JavaScript-Bibliothek, die das Abspielen von HTTP Live Streaming (HLS) in Webbrowsern ermöglicht, ohne dass Plug-ins wie Flash oder Silverlight erforderlich sind. Es ist eine effiziente und leichtgewichtige Lösung für die Wiedergabe von Live- und On-Demand-Videos auf verschiedenen Geräten und Plattformen. HLS.js ist besonders nützlich, wenn es darum geht, das m3u8-Format in der VIS-Oberfläche des ioBrokers abzuspielen.

Webcam-Daten

  1. Wir erstellen einen Http-In den wir “WebcamData” nennen
  2. wir rufen den ioBroker Value für den Stream ab –> Objekt ID netatmo.0.<meine ID>.live.stream
  3. wir schreiben die URL so um, dass wir direkt auf die Variante mit der hohen Auflösung zugreifen können:
    msg.url = msg.payload.replace("index_local.m3u8", "files/high/index_local.m3u8")
  4. Wir rufen per http request die Daten ab
  5. nur in meinem Fall schreibe ich die Daten noch so um, dass sie über meinen Reverse Proxy kommen. Am einfachsten geht das hier durch das 3malige Aufrufen des Replace-Befehls in Schritt 3 . Pro Aufruf wird immer nur das erste Vorkommen ersetzt.
  6. Ausgabe Beispiel:
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-MEDIA-SEQUENCE:22642
#EXT-X-TARGETDURATION:2
#EXTINF:2.000000,
http://192.168.103.7/<DEIN KEY>/live/files/high/live0000022642.ts
#EXTINF:2.000000,
http://192.168.103.7/<DEIN KEY>/live/files/high/live0000022643.ts
#EXTINF:2.000000,
http://192.168.103.7/<DEIN KEY>/live/files/high/live0000022644.ts
VIS Snippet
[
    {
        "id": "bcaf9458c50d0965",
        "type": "http in",
        "z": "9b763ff35c5feced",
        "name": "",
        "url": "/WebcamData",
        "method": "get",
        "upload": false,
        "swaggerDoc": "",
        "x": 790,
        "y": 680,
        "wires": [
            [
                "0ece15db4c681fc0"
            ]
        ]
    },
    {
        "id": "0ece15db4c681fc0",
        "type": "ioBroker get",
        "z": "9b763ff35c5feced",
        "name": "live stream url",
        "topic": "netatmo.0.5838xxxxxxxxxxxxxxxxxxxxxxx.live.stream",
        "attrname": "payload",
        "payloadType": "value",
        "errOnInvalidState": "nothing",
        "x": 800,
        "y": 740,
        "wires": [
            [
                "b6c21be160385f63"
            ]
        ]
    },
    {
        "id": "ce26be8ca988bd7e",
        "type": "http response",
        "z": "9b763ff35c5feced",
        "name": "http Ausgabe",
        "statusCode": "",
        "headers": {},
        "x": 1350,
        "y": 820,
        "wires": []
    },
    {
        "id": "c2d4e4e1c14f825b",
        "type": "http request",
        "z": "9b763ff35c5feced",
        "name": "",
        "method": "GET",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 1170,
        "y": 820,
        "wires": [
            [
                "ce26be8ca988bd7e"
            ]
        ]
    },
    {
        "id": "b6c21be160385f63",
        "type": "function",
        "z": "9b763ff35c5feced",
        "name": "URL umschreiben auf konkreten Endpunkt",
        "func": "msg.url = msg.payload.replace(\"index_local.m3u8\", \"files/high/index_local.m3u8\")\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 880,
        "y": 820,
        "wires": [
            [
                "c2d4e4e1c14f825b"
            ]
        ]
    }
]

Um den Stream anzuzeigen, verwenden wir in VIS das Element iFrame. Damit das etwas anzeigen kann, brauchen wir noch eine Webseite. Diese erstellen wir ebenfalls über den http-Endpunkt in Kombination mit Handlebars (node-red-contrib-handlebars). Eigentlich dient das Element dazu bestimmte werte dynamisch zu ersetzen, aber die Funktion nutzen wir hier nicht, da der Daten-Endpunkt fest ist, aber intern dynamisch erzeugt wird 🙂

VIS Snippet
[
    {
        "id": "a0e0a38d585869e7",
        "type": "http in",
        "z": "9b763ff35c5feced",
        "name": "",
        "url": "/WebcamLive",
        "method": "get",
        "upload": false,
        "swaggerDoc": "",
        "x": 330,
        "y": 120,
        "wires": [
            [
                "e004230d2dc43ac0"
            ]
        ]
    },
    {
        "id": "54a4f4f63669c3e7",
        "type": "http response",
        "z": "9b763ff35c5feced",
        "name": "",
        "statusCode": "",
        "headers": {},
        "x": 750,
        "y": 120,
        "wires": []
    },
    {
        "id": "e004230d2dc43ac0",
        "type": "handlebars",
        "z": "9b763ff35c5feced",
        "name": "Page",
        "sourceProperty": "payload",
        "targetProperty": "payload",
        "query": "<!DOCTYPE html>\n<html>\n\n<head>\n\t<title>Netatmo Security Stream</title>\n\t<script src=\"https://cdn.jsdelivr.net/npm/hls.js@latest\"></script>\n</head>\n\n<body>\n\t<video id=\"my-video\" controls autoplay muted style=\"width:85%; height:auto;float:left\"></video>\n\t<button style=\"width:14%;height: 70px; float:left\" id=\"mute-toggle\">Ton ein/aus</button>\n\n\t<button style=\"margin-top:10px; width:5%;height: 70px; float:left\" id=\"lautstaerke-hoch\">Laut&shy;st&auml;rke +</button>\n\t<input style=\"margin-top:10px; width:4%;height: 65px; float:left;text-align: center;\" id=\"lautstaerke-value\" value=\"0\" />\n\t<button style=\"margin-top:10px; width:5%;height: 70px; float:left\" id=\"lautstaerke-runter\">Laut&shy;st&auml;rke -</button>\n\n\n\t<script>\n\t\tvar video = document.getElementById('my-video');\n\t\tvar videoSrc = 'http://192.168.0.100/WebcamData';\n\t\tvar muteToggle = document.getElementById('mute-toggle');\n\t\tvar lautstaerkeHochButton = document.getElementById('lautstaerke-hoch');\n\t\tvar lautstaerkeRunterButton = document.getElementById('lautstaerke-runter');\n\t\tvar lautstaerkeValue = document.getElementById('lautstaerke-value');\n\t\n\t\t\n\t\n\t\t// Überprüfen Sie, ob HLS.js unterstützt wird\n\t\tif (Hls.isSupported()) {\n\t\t\tvar hls = new Hls();\n\t\t\thls.loadSource(videoSrc);\n\t\t\thls.attachMedia(video);\n\t\t\thls.on(Hls.Events.MANIFEST_PARSED,function() {\n\t\t\t\tvideo.play();\n\t\t\t});\n\t\t} else if (video.canPlayType('application/vnd.apple.mpegurl')) {\n\t\t\tvideo.src = videoSrc;\n\t\t\tvideo.addEventListener('loadedmetadata', function() {\n\t\t\t\tvideo.play();\n\t\t\t});\n\t\t}\n\t\t\n\t\t// Schalten Sie den Ton des Videos ein oder aus, basierend auf dem Zustand des Schalters\n\t\tmuteToggle.addEventListener('click', function() {\n\t\t\tif (video.muted) {\n\t\t\t\tvideo.muted = false;\n\t\t\t\tmuteToggle.innerText = 'Ton ausschalten';\n\t\t\t\tlautstaerkeValue.value = (video.volume * 100).toFixed(0);\n\t\t\t\t\n\t\t\t} else {\n\t\t\t\tvideo.muted = true;\n\t\t\t\tmuteToggle.innerText = 'Ton einschalten';\n\t\t\t\tlautstaerkeValue.value = \"0\";\n\t\t\t}\n\t\t});\n\n\t\t// Erhöhen oder verringern Sie die Lautstärke des Videos basierend auf dem Button, der gedrückt wurde\n\t\tlautstaerkeHochButton.addEventListener('click', function() {\n\t\t\tif (video.volume < 1.0) {\n\t\t\t\tvideo.volume += 0.2;\n\t\t\t}\n\t\t\tvideo.muted = false;\n\t\t\tmuteToggle.innerText = 'Ton ausschalten';\n\t\t\tlautstaerkeValue.value = (video.volume * 100).toFixed(0);\n\t\t});\n\n\t\tlautstaerkeRunterButton.addEventListener('click', function() {\n\t\t\tif (video.volume > 0.0) {\n\t\t\t\tvideo.volume -= 0.2;\n\t\t\t}\n\t\t\tvideo.muted = false;\n\t\t\tmuteToggle.innerText = 'Ton ausschalten';\n\t\t\tlautstaerkeValue.value = (video.volume * 100).toFixed(0);\n\t\t});\n\t</script>\n</body>\n\n</html>",
        "x": 550,
        "y": 120,
        "wires": [
            [
                "54a4f4f63669c3e7"
            ]
        ]
    }
]
<!DOCTYPE html>
<html>

<head>
	<title>Netatmo Security Stream</title>
	<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>

<body>
	<video id="my-video" controls autoplay muted style="width:85%; height:auto;float:left"></video>
	<button style="width:14%;height: 70px; float:left" id="mute-toggle">Ton ein/aus</button>

	<button style="margin-top:10px; width:5%;height: 70px; float:left" id="lautstaerke-hoch">Laut&shy;st&auml;rke +</button>
	<input style="margin-top:10px; width:4%;height: 65px; float:left;text-align: center;" id="lautstaerke-value" value="0" />
	<button style="margin-top:10px; width:5%;height: 70px; float:left" id="lautstaerke-runter">Laut&shy;st&auml;rke -</button>


	<script>
		var video = document.getElementById('my-video');
		var videoSrc = 'http://192.168.0.100:9091/WebcamData';
		var muteToggle = document.getElementById('mute-toggle');
		var lautstaerkeHochButton = document.getElementById('lautstaerke-hoch');
		var lautstaerkeRunterButton = document.getElementById('lautstaerke-runter');
		var lautstaerkeValue = document.getElementById('lautstaerke-value');
	
		
	
		// Überprüfen Sie, ob HLS.js unterstützt wird
		if (Hls.isSupported()) {
			var hls = new Hls();
			hls.loadSource(videoSrc);
			hls.attachMedia(video);
			hls.on(Hls.Events.MANIFEST_PARSED,function() {
				video.play();
			});
		} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
			video.src = videoSrc;
			video.addEventListener('loadedmetadata', function() {
				video.play();
			});
		}
		
		// Schalten Sie den Ton des Videos ein oder aus, basierend auf dem Zustand des Schalters
		muteToggle.addEventListener('click', function() {
			if (video.muted) {
				video.muted = false;
				muteToggle.innerText = 'Ton ausschalten';
				lautstaerkeValue.value = (video.volume * 100).toFixed(0);
				
			} else {
				video.muted = true;
				muteToggle.innerText = 'Ton einschalten';
				lautstaerkeValue.value = "0";
			}
		});

		// Erhöhen oder verringern Sie die Lautstärke des Videos basierend auf dem Button, der gedrückt wurde
		lautstaerkeHochButton.addEventListener('click', function() {
			if (video.volume < 1.0) {
				video.volume += 0.2;
			}
			video.muted = false;
			muteToggle.innerText = 'Ton ausschalten';
			lautstaerkeValue.value = (video.volume * 100).toFixed(0);
		});

		lautstaerkeRunterButton.addEventListener('click', function() {
			if (video.volume > 0.0) {
				video.volume -= 0.2;
			}
			video.muted = false;
			muteToggle.innerText = 'Ton ausschalten';
			lautstaerkeValue.value = (video.volume * 100).toFixed(0);
		});
	</script>
</body>

</html>

in Zeile 20 steht dann die URL vom Endpunkt den wir eben angelegt haben der die m3u8 Datei ausliefert.

Dank Autoplay startet das Video im Fully Kiosk Browser auch sofort. Vom Layout sieht das so aus:

Screenshot beim laden der Seite, bevor Inhalte abgespielt werden.

Hinweis 1: Bei den Tests musste ich lokal den Werbefilter deaktivieren und autoplay wird in chrome z.b. nicht unterstützt – außer es ist eine lokale Webseite (glaube ich)

Hinweis2: das Video startet hier immer muted – das kann man im Video-Element auch entfernen.

Das gezeigte Beispiel kann natürlich auch für andere Kameras genutzt werden die m3u8 Dateien bereitstellen.

Weblinks:

  • https://hlsjs.video-dev.org/demo/

Veröffentlicht unter Heimautomatisierung, Javascript, Programmierung | Verschlagwortet mit , , , , , , , , , , , , , , , , , , , | Ein Kommentar