Suche Programmierer. Datenbank auslesen und visualisieren per Highcharts.

  • In der Zeile 214 der Index.php ist eine Klammer.
    Fehlt die oben drüber, ist sie nur überflüssig bzw. was schließt sie?
    [code=php]<?php
    }
    echo "</div>\n"; // END: content
    [/php]



    Was ist in der funktions.php der untere Abschnitt? Und wo wird das umgesetzt?
    [code=php]function getPeriodUnit($period) {
    $unit = substr($period, -1);
    switch ($unit) {
    case 's': return 'SECOND';
    case 'mi': return 'MINUTE';
    case 'h': return 'HOUR';
    case 'd': return 'DAY';
    case 'w': return 'WEEK';
    case 'm': return 'MONTH';
    case 'y': return 'YEAR';
    }
    }[/php]


    :)


  • Finde ich persönlich jetzt nicht. Wo kann man das denn alles einstellen?
    In welchem Abschnitt werden denn eigentlich die Tooltip bearbeitet?


    Das wird in der index.php jeweils beim erstellen des Charts eingestellt.
    Es werden ja 2 Charts generiert und jeder hat einen eigenen Abschnitt, wobei "Global Chart Options" sind für beide Charts gültig.
    Die künstliche Verzögerung des Temperatur Charts wird über den Abschnitt
    [code=php]
    animation: {
    duration: 2000
    },
    [/php]geregelt bzw eingeschaltet.


    Die Tooltip's werden im gleichnamigen Abschnitt eingestellt.


    Könntest du noch bitte kurz das PHP in der Index-Datei erklären?
    Warum die DIVs als Echo usw. Kenne das so nicht.


    Ein 'echo' ist ein PHP Befehl um eben einen Text oder eine Variable "auszusprechen". Ähnlich wie auf der Linux Konsole zum Beispiel "echo $SHELL" würde dann der Inhalt der Variable SHELL ausgegeben werden (das ist eine Umgebungsvariable also existiert ohne eigenes zutun)


    Entweder man schließt den PHP Abschnitt und fügt dann ohne echo den HTML Code dort ein - was aber ziemlich doof ist und das ganze auch sehr unübersichtlich mach... Oder man fügt für so einzelne Sachen PHP Befehle ein. So werden dann übrigens auch dynamische Abschnitte erzeugt.. Dazu muss man folgendes wissen:


    PHP Wird generell auf dem Server ausgeführt (Serverseitig) und nur eine mögliche Ausgabe wird dem Client angezeigt. Also das PHP Script wird auf dem Server von oben nach unten verarbeitet und nur wenn es Ausgaben gibt wird dies an den Client übermittelt.


    *.php Dateien können auch HTML Code enthalten, aber *.html Dateien können kein PHP Code enthalten da diese dann nicht vom PHP Interpreter (Verarbeiter, Programm) beachtet werden.



    Das erste sind PHP Einstellungen zur Anzeige und Protokollierung von Fehlern sowie ein RAM Limit von 64MB sowie eine Zeitliche Ausführbegrenzung von 30 Minuten... Mehr RAM darf das Script nicht verbrauchen und länger darf das Script nicht ohne Pause ausgeführt werden - das sind einfach nur meine Standard Zeilen...


    Die 'ob' Zeilen sorgen für eine sofortige Ausgabe. Normalerweise gibt es einen sog. Buffer der alle Ausgaben erst zwischenspeichert und erst wenn keine Daten mehr "erwartet" werden, wird dieser Buffer ausgegeben. Durch ein 'flush' wird der Buffer zur Ausgabe gezwungen und geleert, was dann dazu führt das alles sofort dem Client angezeigt wird... Auch nicht zwingend notwendig für diese Project hier aber gehört auch zu meinen Standard-Zeilen :fies:


    Danach hinterlege ich einen Zeitwert in eine Variable um mir dadurch anzeigen zu lassen wie lange die Erstellung der Seite gedauert hat: Duration
    microtime(true); gibt eine Standardisierte Zeit in Form von Sekunden mit MicroSekunden aus, die seit dem 1.1.1970 vergangen sind. So kann ich verstrichene Zeit auch im Millisekunden Bereich errechnen bzw anzeigen.



    Wird eine URI bzw URL bzw Adresse mit solchen Parametern aufgerufen: index.php?bla=blub
    Spricht man von einer sog. GET Übergabe. Diese Werte sind in der global verfügbaren Variable (bzw Array) $_GET abrufbar. Ich prüfe hier also ob es einen 'period' Schlüssel in diesem Array gibt und falls ja wird der Inhalt dieser Variable in $Period hinterlegt. Anschließend schließe ich den PHP Abschnitt weil dann Sachen kommen die nur dann geladen und dem Client angezeigt werden sollen wenn genau dies der Fall ist: Wenn die Adresse in Form von " index.php?period=XXX " aufgerufen wurde.... Nur dann darf und soll er die Charts erstellen - andernfalls würde das ja kein Sinn machen da kein Zeitraum bekannt wäre.


    Danach setze ich erneut eine Zeitvariable um dann die Duration zu errechnen - dienlich als Information wie lange das generieren der Seite, das verarbeiten des Codes, gedauert hat.



    Das gehört zu dem gerade angesprochenen Abschnitt. Hier schließe ich wieder die ' if ' Abfrage von der $_GET['period'] Sache ;) Die Zeilen die da zwischen stehen werden wie gesagt nur dann beachtet wenn $_GET['period'] gesetzt ist.


    Werden Themes einfach in den Ordner kopiert und fertig?


    Im Archiv hab ich jetzt nix gefunden. Aber hier:
    https://github.com/highslide-s…com/tree/master/js/themes


    Sie müssen auch geladen werden. Ich lade zum Beispiel: [code=php]<script src='highcharts/js/themes/grid.js'></script>[/php]..wie du sie auch in dem von dir angegebenen Link findest..


    Ich hatte mir das Archive http://code.highcharts.com/zips/Highcharts-4.1.8.zip geladen und da drin sind alle Dateien/Ordner.


    Gibts eigentlich einen bestimmten Grund warum die Charts nicht auf dem Handy/Tablet angezeigt werden?


    Da ich weder Handy noch Tablet habe, konnte ich diesen Teil nicht testen ;)



    Funktionen sind quasi Befehle die man definiert.


    getPeriodUnit(); wird in der data.php verwendet um in der SQL Abfrage den Zeitraum festzulegen:


    [code=php]
    $result = query("SELECT id,location FROM data GROUP BY location");
    while ($row = mysqli_fetch_array($result)) {
    $data = array();
    $data['name'] = $row['location'];
    // Get Data from each "location"
    $result2 = query("SELECT location,timestamp,".$Type." FROM data
    WHERE location = '".$row['location']."'
    AND timestamp >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL ".$PeriodNum." ".getPeriodUnit($Period)."))
    AND timestamp <= UNIX_TIMESTAMP()
    ORDER BY timestamp ASC
    ;");
    while ($row2 = mysqli_fetch_array($result2)) {
    $data['data'][] = array((float)($row2['timestamp']*1000), (float)$row2[$Type]);
    }
    array_push($dataResult, $data);
    }
    [/php]


    $Period beinhaltet zum Beispiel: 1w
    Dann versucht getPeriodUnit($Period); davan die Einheit festzustellen: w
    Und gibt dann den vollständigen Namen der Einheit aus: WEEK

  • Versuch es mal mit folgendem Python3 Script - konnte das aber nicht genauer testen da ich keine 1-Wire Sensoren habe:


    [code=php]
    #!/usr/bin/python3
    # coding: utf-8
    #
    # Read 1-Wire sensors and write into database
    # 06.10.2015 by meigrafd
    #
    # NOTE:
    # Im using CyMySQL which is a fork of pymysql with C speedups. See http://stackoverflow.com/a/25724855
    #
    #------------------------------------------------------------------------


    # Specify Settings for MySQL: Host, Port, Login and Password
    mysqlHost = '127.0.0.1'
    mysqlPort = '3306'
    mysqlLogin = 'root'
    mysqlPass = 'raspberry'
    mysqlDatabase = "measurements"


    sensor_dict={}
    # 1wire Sensor Path and Place.
    # Format: sensor_dict["<path>"] = "<Place>"
    # E.g.: sensor_dict["/sys/bus/w1/devices/10-000801b5a7a6/w1_slave"] = "Bath"
    sensor_dict["/sys/bus/w1/devices/10-000801b5a7a6/w1_slave"] = "Badezimmer"
    sensor_dict["/sys/bus/w1/devices/10-000801b5959d/w1_slave"] = "Wohnzimmer"


    #------------------------------------------------------------------------
    import sys, time, os, re
    try:
    import cymysql
    except ImportError:
    print("ERROR: You must install cymysql Module: sudo apt-get install python3-pip && sudo pip-3.2 install cymysql")
    exit()
    if not os.path.exists("/sys/bus/w1/devices/w1_bus_master1/w1_master_slave_count"):
    print("ERROR: w1 Kernel Module not loaded?")
    print("With Kernel >= 3.18:")
    print(" echo dtoverlay=w1-gpio >> /boot/config.txt")
    print("or")
    print(" echo dtoverlay=w1-gpio-pullup >> /boot/config.txt")
    print("With older Kernels add:\n w1-gpio\n w1-therm\nto /etc/modules")
    exit()
    if open("/sys/bus/w1/devices/w1_bus_master1/w1_master_slave_count").read(1000).startswith("0"):
    print("ERROR: No 1-wire Sensors connected?")
    exit()


    # This handles console colors used for print's
    #http://misc.flogisoft.com/bash/tip_colors_and_formatting
    class c:
    ENDC='\33[0m'
    DEFAULT='\33[39m'; BOLD='\33[1m'; DIM='\33[2m'
    RESBOLD='\33[21m'; RESDIM='\33[22m'
    RED='\33[31m'; GREEN='\33[32m'; YELLOW='\33[33m'; CYAN='\33[36m'


    def read_sensor(path):
    value=None
    try:
    f = open(path, 'r')
    line = f.readline()
    if re.match(r"([0-9a-f]{2} ){9}: crc=[0-9a-f]{2} YES", line):
    line = f.readline()
    m = re.match(r"([0-9a-f]{2} ){9}t=([+-]?[0-9]+)", line)
    if m:
    value = str(float(m.group(2)) / 1000.0)
    f.close()
    except (IOError) as e:
    print(time.strftime("%x %X"), c.BOLD+c.RED+"Error reading"+c.ENDC, path, ": ", e.strerror)
    return value


    def get_data():
    for sensorPath in sensor_dict:
    sensorPlace = sensor_dict.get(sensorPath)
    data = read_sensor(sensorPath)
    if data:
    print('{} -> {}'.format(sensorPlace, data))
    addData(sensorPlace, data)
    else:
    print('{} -> None'.format(sensorPlace))


    def addData(Place, Data):
    Timestamp = int(time.time())
    con = None
    try:
    con = cymysql.connect(host=mysqlHost, port=int(mysqlPort), user=mysqlLogin, passwd=mysqlPass)
    cur = con.cursor()
    cur.execute("CREATE DATABASE IF NOT EXISTS %s;" % mysqlDatabase)
    cur.execute("USE %s;" % mysqlDatabase)
    con.commit()
    cur.execute("CREATE TABLE IF NOT EXISTS data (id INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,location VARCHAR(255),timestamp INT(11),temp FLOAT(11),hum FLOAT(11),KEY location (location)) ENGINE=InnoDB DEFAULT CHARSET=utf8;")
    con.commit()
    cur.execute("INSERT INTO data (timestamp, location, temp) VALUES (%s,%s,%s);", (Timestamp, Place, Data))
    con.commit()
    except Exception as err:
    print(c.BOLD+c.RED+"MySQL Error: "+str(err)+c.ENDC)
    except (KeyboardInterrupt, SystemExit):
    exit()
    finally:
    if con:
    con.close()


    if __name__ == '__main__':
    try:
    get_data()
    except (KeyboardInterrupt, SystemExit):
    print("\nSchliesse Programm..")
    [/php]Es beachtet zudem nur 'temp' da mir keine 1-Wire Sensoren mit 'hum' bekannt sind.

  • Hey super!


    Werds testen.
    Falls du gerne auch so mal testen magst, kann ich dir gerne mal 2 Sensoren schicken.
    Ist ja kein Aufwand.


    Wie meinst das mit dem "hum"?
    Für den DHT brauchts ja eh ein extra Script, oder nicht?



    Edit:
    E: Paket cymysql kann nicht gefunden werden.


    Woher kommt das Paket?

  • Eigentlich gibt das Script genaue Anweisungen aus um das CyMySQL Module zu installieren:

    Code
    apt-get install python3-pip && pip-3.2 install cymysql

    ..wenn du kein root bist dann natürlich mit 'sudo' davor:

    Code
    sudo apt-get install python3-pip && sudo pip-3.2 install cymysql
  • Hoppla. Hab das zweite sudo vergessen. :stumm:
    Nu klappt das.


    Allerdings:

  • OK.
    Ist umbenannt und es kommt nun das:


  • Was macht das Script eigentlich wenn der Sensor einen Fehler ausgibt?
    Bzw. er nicht "YES" meldet. Ich kann das im Script nicht wirklich zuordnen.


    Klappt bei dir das eigentlich mit dem Sunset/ Sunrise?

  • Wenn der Sensor kein YES Status hat passiert garnichts, dann gibt nur das Script "None" aus aber es wird natürlich nichts eingetragen. Man könnte das ggf erweitern indem er dann zB weitere 5x versucht den Sensor auszulesen bis kein None mehr zurück gegeben wird.


    Sunset/Sunrise hab ich noch nicht eingebaut - das ist bissal komplizierter als gedacht :X


    Hab die addData Funktion in Beitrag#23 noch mal angepasst und nun sollte es keine Fehler vom Script mehr geben.
    Nun ist mir aber noch ein Fehler bezüglich dem erstellen des Humidity Charts aufgefallen: Auch wenn keine Messwerte existieren wird die 'location' abgebildet, was aber bissal blöd ist :(

  • Juhu! :D
    Es scheint zu klappen! Ich lass es nunmal länger laufen.
    Ja, eine Wiederholung im Fehlerfall wäre nicht schlecht. 2x müsste doch reichen?
    Würde im Fehlefall eine Printausgabe unter dem Chart gehen? (Etwa wie: Achtung! Sensor/en "xyz" konnte nicht gelesen werden!)


    Stimmt, Sunset/Sunrise ist nicht so einfach wie "er" das beschreibt.


    Hm, ja das mit dem Chart in Luftfeuchte ist nicht ganz so schön. Da hast recht.


    Aber immerhin gehts :danke_ATDE:

  • Bis jetzt klappt es problemlos. ;)
    Zum Testen hab ich zwar noch nicht alle Sensoren dran, sollte aber dennoch gehen. Auch wen die Leitung dann etwas länger wird.


    Heute kamen auch endlich die 2 DHT Sensoren. Werde die baldmöglichst testen.
    Ich hoffe das klappt dann auch mit dem Eintragen in die Datenbank.


    Du dachtest auch das es ein Fehler im Chart der Luftfeuchte ist, aber das scheint wohl normal zu sein. Zumindest ist mir das noch in 2 anderen Charts aufgefallen.
    Hab mich allerdings schon daran gewöhnt.



    Mit dem Sonnenstand bin ich allerdings noch am suchen. Viel Infos gibts leider nicht im Netz.


    PS
    Die Zoom-Funktion in den Highcharts ist übrigens auch sehr nett und nützlich.
    chart: {
    zoomType: 'x'
    },

  • Ich hab gestern noch mal Zeit gefunden an dem Projekt weiter zu werkeln und hab dabei folgendes geändert:

    • Deine CSS Einstellungen übernommen
    • "zoomType" eingefügt sowie im "subtitle" ein Hinweis darauf das man zoomen kann ;)
    • Künstliche Verzögerung beim Zeichnen (animation) entfernt.
    • Tooltip auf Standard gelassen, da ich das wie erwähnt besser finde - insbesondere die Anzeige vom Datum finde ich bei Langzeitmessungen wichtig, da das in der X Achse nicht angegeben wird.
    • Footer auskommentiert da das nicht das auslesen der Daten Ansich bemisst und die Seite auch unnötig vergrößert.
    • 'title' Anzeige bei den Links im Menü.
    • Erkennung der Anzeige-Einheiten (Unit) verbessert. Nun wird auch "Minutes" als Unit "mi" supported. (Selectable Chart Ranges)
    • Zusätzliches Highcharts Module eingebunden: no-data-to-display.js
    • Wenn keine Daten vorhanden sind wird die 'location' auch nicht mehr im Chart angezeigt. Dies war ja besonders beim Feuchtigkeits-Chart ein Problem.


    Nun fehlt also nur noch die Sunset/Sunrise Geschichte...


    Noch mal zusammenfassend die Struktur:


    Desweiteren habe ich mich noch mal an das Python Script gesetzt, denn eigentlich gibt es kein Grund wieso man zwei Scripts laufen lassen müsste. Man kann die DHT22 (auch bekannt als AM2302) auch mit Python direkt auslesen, wobei ich persönlich einen anderen Weg finden wollte als der allgemein übliche über Adafruit_DHT ... Zusätzlich gefiel mir auch der Gedanke, an andere PI's angeschlossene DHT22 Sensoren übers Netzwerk mithilfe von pigpio auszulesen und ebenfalls zentral in die Datenbank einzutragen.
    Bei meiner Recherche bin ich dann auf diesen Thread gestoßen. Da setz ich mich jetzt erst mal dran das mit einzubauen.



    Der aktuelle Code ist nun auf meinen Github Repo verfügbar: https://github.com/meigrafd/HighCharts


    Demo: http://raspberrypi.roxxs.org/charts/?period=1y

  • ! Stark!! :thumbs1:


    Und meine DHT funktionieren soweit auch und lassen sich auslesen. Ich bin schon gespannt.
    Hatte es jetzt zum Testen mit wiringPi gemacht.
    Mach ich also besser pigpio drauf?


    Quote


    7. Erkennung der Anzeige-Einheiten (Unit) verbessert. Nun wird auch "Minutes" als Unit "mi" supported. (Selectable Chart Ranges)
    8. Zusätzliches Highcharts Module eingebunden: no-data-to-display.js
    9. Wenn keine Daten vorhanden sind wird die 'location' auch nicht mehr im Chart angezeigt. Dies war ja besonders beim Feuchtigkeits-Chart ein Problem.



    7. Was ist das genau?
    8 u. 9 gehören zusammen?



    Hilft zur Sunset-Geschichte evtl das weiter?


    Nur ein einziges Skript zum Auslesen der Sensoren wäre natürlich super.



    Tooltip find ich übrigens so recht gut leserlich
    [code=php]formatter: function () {
    return '<b>' + this.series.name + '</b> <br/> ' + Highcharts.dateFormat('%e %b um %H:%M', this.x)+'<br/>' + ' = ' + this.y.toFixed(1) + '°C';
    }[/php]


    Da dir Highcharts ja auch so gut gefallen, wollte ich nicht unerwähnt lassen das es auch eine Scrollbar gibt ;)
    Ob das dann in Verbindung mit dem Zoom dann auch so gut geht kann ich nicht sagen.

    Images

    • bild2.png

    Raspi 3 mit Kodi 18 + Netflix & Amazon

    Raspi2 B+ als Datenlogger                            

  • Mach ich also besser pigpio drauf?


    pigpio ist generell mächtiger als wiringPi, allerdings deshalb auch nicht so benutzerfreundlich. Du kannst aber problemlos beides installiert haben.


    7. Was ist das genau?
    8 u. 9 gehören zusammen?


    7. bezieht sich auf die Einheiten in der config.php... Zum Beispiel von " 30mi " ist die Einheit "mi" und bezieht sich auf "Minutes". Siehe config.php
    Es müssen ja nur die Daten aus der Datenbank abgefragt werden die in einen gewissen Zeitrahmen gehören, also zB nur die Daten der letzten 30 Minuten. Zuvor hatte ich einfach nur die letzte Stelle als Unit verwendet, was aber nicht funktioniert wenn es 2 Stellen sind. Nun habe ich das so das generell alle Zahlen aus dieser Period-Angabe rausgefiltert werden um dann die Unit zu erhalten. Siehe dazu data.php oder functions.php



    8. und 9. haben eigentlich nichts miteinander zu tun. Klick mal in der Demo auf "Last 30mi", dann siehst du das was 8. bewirkt -> No data to display. Mehr macht das Module nicht - aber das ist besser als einfach nur ein leere Chart ;)
    Und bei 9. war ja das Problem das trotz keiner Messwerte die location trotzdem eingezeichnet wurde. Also zum Beispiel in meiner Demo, wurde trotzdem "Wohnzimmer" mit 0°C eingezeichnet obwohl es dafür keine Daten gab...

  • Ok, das hab ich dann soweit Verstanden, danke.


    Bei "CREATE TABLE `data` " bist du von latin zu utf8.
    das "not null" fehlt.
    Ist das beabsichtigt und macht es was wegen der alten Tabelle?


    Als Anregung.
    Wenn das Menü in einer Liste (<li> </li>) dargestellt wird, dann läst es sich auch recht einfach per CSS anpassen. ;)


    [code=php]echo "<div id='menu'>\n";
    foreach ($Chart AS $PERIOD => $DESCRIPTION) {
    echo "<li> <a href='?period=".$PERIOD."' title='".$DESCRIPTION."'>Last ".$PERIOD."</a></li>\n";
    }
    echo "</div>\n";[/php]

  • Desweiteren habe ich mich noch mal an das Python Script gesetzt, denn eigentlich gibt es kein Grund wieso man zwei Scripts laufen lassen müsste. Man kann die DHT22 (auch bekannt als AM2302) auch mit Python direkt auslesen, wobei ich persönlich einen anderen Weg finden wollte als der allgemein übliche über Adafruit_DHT ... Zusätzlich gefiel mir auch der Gedanke, an andere PI's angeschlossene DHT22 Sensoren übers Netzwerk mithilfe von pigpio auszulesen und ebenfalls zentral in die Datenbank einzutragen.
    Bei meiner Recherche bin ich dann auf diesen Thread gestoßen. Da setz ich mich jetzt erst mal dran das mit einzubauen.


    Hi.
    Konntest du hier eigentlich weiter kommen? :)


    Ansonsten halt mehrere Skripte.

  • Hallo zusammen,


    bin ganz frisch hier im Forum und auch im Kennenlernen des Raspberry´s.


    Möchte perspektivisch den Pi zum loggen der Temperaturen unserer 10 Jahre alten Wärmepumpe einsetzen. Habe mir bereit diverse DS18S20 besorgt und diese auch angeschlossen.
    Im Terminal ist es mir auch bereits gelungen, die Sensoren zu erkennen(ID-NR.-Auflistung) und einzeln auszulesen. Aber das war`s dann leider auch schon.


    Lese seit etwa einer Woche intensiv im Forum - habe aber leider noch zu wenig Grund-Kenntnisse, um die vielen Informationen richtig anzuwenden. Komme beruflich aus dem SPS-Bereich, wo ich nur mit KOP.AWL oder FUP programmiere.


    Habe jetzt mal versucht, dieses sehr interessante Projekt auf dem Pi zu installieren - leider fehlt mir das Verzeichniss /var/www ... . Wenn ich versuche, dieses einzurichten, bekomme ich die Meldung, das ich dazu keine Berechtigung habe. Leider finde ich über die Such-Funktion im Forum nichts dazu, wie ich diese erlangen kann.


    Ich hoffe, die Frage ist nicht zu trivial und es gilt noch der Anfänger-Bonus bei euch.


    Besten Dank - towi :danke_ATDE:

  • Hallo nochmal zusammen,


    hat mir keine Ruhe gelassen - Verzeichnisserstellung ist mir gelungen - wieder was gelernt.


    Übrigens befolge ich die Installationsanweisung aus der README-Datei!


    ABER: Die Datei 1wire.py ließ sich nicht nach /usr/local/sbin verschieben - habe dazu vorher in das Verzeichniss /var/www/charts/HighCharts/ gewechselt - dann hat`s geklappt. Hoffe das war richtig?


    Weitere Frage: Was soll man in nach nachfolgenden zwei sudo nano`s eintagen?


    Würde die Installation erst danach fortsetzen wollen.


    Nochmals besten Dank!!!


  • Weitere Frage: Was soll man in nach nachfolgenden zwei sudo nano`s eintagen?



    Hi,


    bin leider etwas spät dran.
    Aus deiner Frage werde ich nicht schlau. Was meinst du da genau?