d3 Einstieg

Wie wir in den früheren Posts gesehen haben, kann man mit Skripten und Vis relativ viel machen, um die Funktion von ioBroker zu erweitern und zu visualisieren.
Allerdings hat der einfache Zugang auch seine Nachteile:
  • Debuggen ist umständlich. Umfangreichere und modulare Skripte sind darum schwierig.
  • Man ist für die Visualisierung zunächst mal auf existierende Widgets festgelegt. Zwar kann man das DOM "von Hand" manipulieren, aber das wird bei grösseren Projekten schnell zum Albtraum.
Ich vermisse die gewohnten Frameworks wie D3 oder Aurelia und die umfassenden Edit- und Debugmöglichkeiten einer Entwicklungsumgebung wie Idea oder auch nur eines komfortablen Editors wie Atom.

Glücklicherweise ist das kein Problem. Der ioBroker-Adapter "simpleAPI" aus der Gruppe "Kommunikation" stellt eine REST-Schnittstelle zum Auslesen und Setzen von States bereit. Dieses API kann man mit beliebigen Programmen in irgendeiner Programmiersprache, die REST-Anfragen absetzen kann, benutzen.

Zum Einstieg nur eine kleine Fingerübung: Ich will die Leistung des Fronius Inverters mit d3 auslesen.

Dazu erstellen wir zunächst eine simple HTML-Datei namens index.html und folgendem Inhalt:

1 <!DOCTYPE html>
2 <title>Homeview</title>
3 <h1>Test</h1>
4 <div class="container">
5     <div id="graph"></div>
6 </div>
7 <script src="http://d3js.org/d3.v4.min.js"></script>
8 <script src="code.js"></script>

und im selben Verzeichnis eine Datei namens code.js und folgendem Inhalt:

 1 var server="192.168.16.140:8087";
 2 var fronius="fronius.0.powerflow.P_PV";
 3 var width=900, height=300,padding=25;
 4 var x=d3.scaleLinear().range([padding,width-padding])
 5   .domain([0,10000]);
 6 
 7 var xAxis=d3.axisBottom(x);
 8 
 9 var svg=d3.select("#graph").append("svg")
10   .attr("width",width)
11   .attr("height",height);
12 
13 svg.append("g").call(xAxis)
14 
15 d3.json("http://"+server+"/get/"+fronius,function(result){
16   var val=x(result.val)
17   var bar=svg.append("rect")
18   .attr("x",x(0))
19   .attr("width",function(){
20     return val-x(0)
21   })
22   .attr("y",padding)
23   .attr("height",50)
24   .attr("fill","yellow")
25   .attr("stroke","blue")
26 });

In den ersten beiden Zeilen definieren wir die Adresse des Heimservers und den Datenpunkt, den wir auslesen wollen (Natürlich können Sie auch irgend etwas Anderes nehmen, wenn Sie keinen Fronius Wechselrichter zur Hand haben). Zeile 3 legt die Grösse des Anzeigebereichs fest.

In Zeile 4 teilen wir d3 mit, dass wir Werte zwischen 0 und 10000 erwarten (domain), die bitte auf Bildschirmbereiche zwischen 25 und 875 abzubilden sind (range). Damit erledigt d3 das Skalieren der Daten für uns.

Ab Zeile 15 wird der aktuelle Wert der Photovoltaikanlage ausgelesen und im Anzeigebereich dargestellt.

Um das auszuprobieren, starten Sie einen Webserver. Da auf den meisten Maschinen von Webentwicklern (und solchen, die es werden wollen), ohnehin PHP installiert ist, bietet es sich an, den in php integrierten Mini-Server zu verwenden. Gehen Sie mit einem Terminal ins Verzeichnis, in dem oben genannte Dateien gespeichert sind und geben Sie ein: php -S localhost:9000. Dann können Sie mit Ihrem Lieblingsbrowser auf http://localhost:9000 gehen, um das Resultat obiger Bemühungen zu sehen.



Nun, das ist nicht revolutionär, zugegeben (und man hätte es auch mit direktem Zugriff auf das REST-API des Fronius Inverters machen können), aber das Faszinierende ist, dass man auf so einfache Weise mit vereinheitlichtem Zugriff dank des Standard-Interfaces von ioBroker auf eine Vielzahl von Heimautomations-Komponenten zugreifen kann. Und mit der hier gezeigten Methode ist man dabei nicht auf die limitierten Möglichkeiten des JavaScript-Adapters beschränkt. Als zusätzlichen Bonus nimmt einem das JavaScript Interface von ioBroker den Ärger mit den CORS-Sicherheitsmechanismen der Browser ab, weil es (im Gegensatz zu vielen REST-fähigen iot-Geräten) die korrekten CORS-Header liefert.

Am Schluss dieses Teils noch eine kleine Verbesserung: Obiges Beispiel ist ja statisch. Wenn man einen aktualisierten Wert will, muss man die Seite neu laden. Das geht besser:

const server="192.168.16.140:8087";
const fronius="fronius.0.powerflow.P_PV";
const width=900, height=300,padding=25;
const x=d3.scaleLinear().range([padding,width-padding])
  .domain([0,10000]);

const xAxis=d3.axisBottom().scale(x).tickFormat(function (d) {
  return x.tickFormat(12,d3.format(",d"))(d)})

const svg=d3.select("#graph").append("svg")
  .attr("width",width)
  .attr("height",height);

svg.append("g")
  .attr("class","axis")
  .attr("transform","translate(0,80)")
  .call(xAxis)

const bar=svg.append("rect")
  .attr("x", x(0))
  .attr("y",padding)
  .attr("height",50)
  .attr("fill","yellow")
  .attr("stroke","blue")

const text=svg.append("text")
  .attr("class","textval")
  .attr("x",padding+5)
  .attr("y",padding+25)

setInterval(update,10000)
update()

async function update(){
  const result=await fetch(`http://${server}/get/${fronius}`)
  const power=await result.json()
  bar.attr("width", x(power.val)-x(0))
  text.text(`${power.val} Watt`)
}

Im Prinzip tut dieses Script exakt dasselbe, wie das Vorherige, nur dass es alle veränderlichen Werte in der "update()" Funktion alle 10 Sekunden aktualisiert.
Ausserdem habe ich hier auf den neueren JavaScript-Dialekt ECMA Script 6 gewechselt, d.h. für dieses Script brauchen Sie einen einigermassen aktuellen Browser.

Wenn Sie lieber eine logarithmische Darstellung der Momentleistung haben wollen (der Bereich zwischen 500 und 5000 Watt ist wichtiger, als der ohnehin selten Erreichte über 8000), dann ändern Sie die entsprechenden Zeilen so:

4 const x=d3.scaleLog().range([padding,width-padding])
5   .domain([100,10000]).base(10);
6 
7 const xAxis=d3.axisBottom().scale(x).tickFormat(function (d) {
8   return x.tickFormat(12,d3.format(",d"))(d)})

Das Ergebnis ist dann:


Beachten Sie, dass ich hier die Skala bei 100 starten lasse. Einerseits ist das, um nicht zuviel Platz für irrelevante Werte unter 100 Watt zu verbrauchen, andererseits wäre der Wert 0 als Startpunkt ohnehin unmöglich, weil log(0) mathematisch undefiniert ist,

Kommentare

Beliebte Posts aus diesem Blog

von Schedules und Triggern

myStrom WiFi Button an ioBroker anbinden

Einfache Script-Beispiele