Python Script Ausgabe in CSV

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo,

    Ich habe den RPi in der Tinkerforge Wetterstation verbaut und den Python-Democode am Laufen.ä
    Der Start erfolgt per rc.local derzeit...

    Nun gibt das Script die Daten der Wettersensoren auf der Konsole aus und auf dem Display der Wetterstation.
    Ich würde gerne die Daten in einer CSV-Datei speichern... Kann man die Textausgabe in eine solche Datei umleiten?

    Wäre super... Wenn das man einfach ginge...

  • Das sollte eigentlich kein Problem sein. So wie ich das verstehe bekommst Du die Daten auf der Konsole. Die kann man umleiten in eine Datei und dann für csv aufbereiten. Um Dir da bei der Konvertierung helfen zu können musst Du aber ein paar Beispielsdaten posten.

  • Na, das wäre total super... es soll die Daten in eine CSV-Datei schreiben, aber am liebsten nicht endlos, sondern vielleicht max. 1 Woche. Und wenn sich das Script dann noch zu einer bestimmten Zeit beendet, wäre das total super...

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-

    import socket
    import sys
    import time
    import math
    import logging as log
    import httplib
    import json
    import threading
    log.basicConfig(level=log.INFO)

    from tinkerforge.ip_connection import IPConnection
    from tinkerforge.ip_connection import Error
    from tinkerforge.brick_master import Master
    from tinkerforge.bricklet_lcd_20x4 import LCD20x4
    from tinkerforge.bricklet_ambient_light import AmbientLight
    from tinkerforge.bricklet_humidity import Humidity
    from tinkerforge.bricklet_barometer import Barometer

    class Xively:
    HOST = 'api.xively.com'
    AGENT = "Tinkerforge xively 1.0"
    FEED = '105813.json'
    API_KEY = 'WtXx2m6ItNZyFYoQyR5qnoN1GsOSAKxPMGdIaXRLYzY5ND0g'

    def __init__(self):
    self.items = {}
    self.headers = {
    "Content-Type" : "application/x-www-form-urlencoded",
    "X-ApiKey" : Xively.API_KEY,
    "User-Agent" : Xively.AGENT,
    }
    self.params = "/v2/feeds/" + str(Xively.FEED)
    self.upload_thread = threading.Thread(target=self.upload)
    self.upload_thread.daemon = True
    self.upload_thread.start()

    def put(self, identifier, value):
    try:
    _, min_value, max_value = self.items[identifier]
    if value < min_value:
    min_value = value
    if value > max_value:
    max_value = value
    self.items[identifier] = (value, min_value, max_value)
    except:
    self.items[identifier] = (value, value, value)

    def upload(self):
    while True:
    time.sleep(5*60) # Upload data every 5min
    if len(self.items) == 0:
    continue

    stream_items = []
    for identifier, value in self.items.items():
    stream_items.append({'id': identifier,
    'current_value': value[0],
    'min_value': value[1],
    'max_value': value[2]})

    data = {'version': '1.0.0',
    'datastreams': stream_items}
    self.items = {}
    body = json.dumps(data)

    try:
    http = httplib.HTTPSConnection(Xively.HOST)
    http.request('PUT', self.params, body, self.headers)
    response = http.getresponse()
    http.close()

    if response.status != 200:
    log.error('Could not upload to xively -> ' +
    str(response.status) + ': ' + response.reason)
    except Exception as e:
    log.error('HTTP error: ' + str(e))

    class WeatherStation:
    HOST = "localhost"
    PORT = 4223

    ipcon = None
    lcd = None
    al = None
    hum = None
    baro = None

    def __init__(self):
    self.xively = Xively()
    self.ipcon = IPConnection()
    while True:
    try:
    self.ipcon.connect(WeatherStation.HOST, WeatherStation.PORT)
    break
    except Error as e:
    log.error('Connection Error: ' + str(e.description))
    time.sleep(1)
    except socket.error as e:
    log.error('Socket error: ' + str(e))
    time.sleep(1)

    self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE,
    self.cb_enumerate)
    self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED,
    self.cb_connected)

    while True:
    try:
    self.ipcon.enumerate()
    break
    except Error as e:
    log.error('Enumerate Error: ' + str(e.description))
    time.sleep(1)

    def cb_illuminance(self, illuminance):
    if self.lcd is not None:
    text = 'Illuminanc %6.2f lx' % (illuminance/10.0)
    self.lcd.write_line(0, 0, text)
    self.xively.put('AmbientLight', illuminance/10.0)
    log.info('Write to line 0: ' + text)

    def cb_humidity(self, humidity):
    if self.lcd is not None:
    text = 'Humidity %6.2f %%' % (humidity/10.0)
    self.lcd.write_line(1, 0, text)
    self.xively.put('Humidity', humidity/10.0)
    log.info('Write to line 1: ' + text)

    def cb_air_pressure(self, air_pressure):
    if self.lcd is not None:
    text = 'Air Press %7.2f mb' % (air_pressure/1000.0)
    self.lcd.write_line(2, 0, text)
    self.xively.put('AirPressure', air_pressure/1000.0)
    log.info('Write to line 2: ' + text)

    temperature = self.baro.get_chip_temperature()/100.0
    # \xDF == ° on LCD 20x4 charset
    text = 'Temperature %5.2f \xDFC' % temperature
    self.lcd.write_line(3, 0, text)
    self.xively.put('Temperature', temperature)
    log.info('Write to line 3: ' + text.replace('\xDF', '°'))

    def cb_enumerate(self, uid, connected_uid, position, hardware_version,
    firmware_version, device_identifier, enumeration_type):
    if enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED or \
    enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE:
    if device_identifier == LCD20x4.DEVICE_IDENTIFIER:
    try:
    self.lcd = LCD20x4(uid, self.ipcon)
    self.lcd.clear_display()
    self.lcd.backlight_on()
    log.info('LCD20x4 initialized')
    except Error as e:
    log.error('LCD20x4 init failed: ' + str(e.description))
    self.lcd = None
    elif device_identifier == AmbientLight.DEVICE_IDENTIFIER:
    try:
    self.al = AmbientLight(uid, self.ipcon)
    self.al.set_illuminance_callback_period(1000)
    self.al.register_callback(self.al.CALLBACK_ILLUMINANCE,
    self.cb_illuminance)
    log.info('AmbientLight initialized')
    except Error as e:
    log.error('AmbientLight init failed: ' + str(e.description))
    self.al = None
    elif device_identifier == Humidity.DEVICE_IDENTIFIER:
    try:
    self.hum = Humidity(uid, self.ipcon)
    self.hum.set_humidity_callback_period(1000)
    self.hum.register_callback(self.hum.CALLBACK_HUMIDITY,
    self.cb_humidity)
    log.info('Humidity initialized')
    except Error as e:
    log.error('Humidity init failed: ' + str(e.description))
    self.hum = None
    elif device_identifier == Barometer.DEVICE_IDENTIFIER:
    try:
    self.baro = Barometer(uid, self.ipcon)
    self.baro.set_air_pressure_callback_period(1000)
    self.baro.register_callback(self.baro.CALLBACK_AIR_PRESSURE,
    self.cb_air_pressure)
    log.info('Barometer initialized')
    except Error as e:
    log.error('Barometer init failed: ' + str(e.description))
    self.baro = None

    def cb_connected(self, connected_reason):
    if connected_reason == IPConnection.CONNECT_REASON_AUTO_RECONNECT:
    log.info('Auto Reconnect')

    while True:
    try:
    self.ipcon.enumerate()
    break
    except Error as e:
    log.error('Enumerate Error: ' + str(e.description))
    time.sleep(1)

    if __name__ == "__main__":
    log.info('Weather Station: Start')

    weather_station = WeatherStation()

    if sys.version_info < (3, 0):
    input = raw_input # Compatibility for Python 2.x
    input('Press key to exit\n')

    if weather_station.ipcon != None:
    weather_station.ipcon.disconnect()

    log.info('Weather Station: End')


  • Ja natürlich geht das, wird auch in der Doku gut beschrieben: http://docs.python.org/2/tutorial/inp…d-writing-files

    Das Lesen aus einer Datei mit Python ist Basic :dodgy: Die primäre Frage ist in welchem Format die Ausgabedaten vorliegen so dass die in csv konvertiert werden können.

    DVB: Na dann man los :rolleyes:

    blebbens: Leichter ist es wenn Du uns Beispielsausgabedaten lieferst.

  • Die Ausgabe ändert sich sekündlich:
    INFO:root:Write to line 1: Humidity 39.30 %
    INFO:root:Write to line 0: Illuminanc 0.10 lx
    INFO:root:Write to line 2: Air Press 1017.03 mb
    INFO:root:Write to line 3: Temperature 28.80 °C
    INFO:root:Write to line 0: Illuminanc 0.00 lx
    INFO:root:Write to line 1: Humidity 39.40 %
    INFO:root:Write to line 2: Air Press 1017.03 mb
    INFO:root:Write to line 3: Temperature 28.79 °C
    INFO:root:Write to line 2: Air Press 1017.05 mb
    INFO:root:Write to line 3: Temperature 28.80 °C
    INFO:root:Write to line 1: Humidity 39.50 %
    INFO:root:Write to line 0: Illuminanc 0.10 lx
    INFO:root:Write to line 2: Air Press 1017.06 mb
    INFO:root:Write to line 3: Temperature 28.80 °C
    INFO:root:Write to line 1: Humidity 39.40 %
    INFO:root:Write to line 0: Illuminanc 0.20 lx

    Aber er soll nicht sekündlich die CSV erstellen, sondern alle 10 Minuten...

    • Offizieller Beitrag

    ich glaube nicht das ne csv an der Stelle sinn macht, da dank threading keine zusammenhängenden Datensets zurückgegeben werden (Hum , kann vor Air Press kommen oder auch nicht). Entweder ballerst du alles in eine richtige Datenbank oder man schreibt das script um und in dem Fall würde ich auf threading verzichten . Wie oft muss den Display aktualisiert werden? reichen da auch 10min? so das man mit nem einfachen "wait" den aktualisierungs/ speicherintervall bestimmen könnte.

    Und ja, es werden mehr als 3 Zeilen Änderungen :)

    btw. code tags rocken ;). python ohne seine grossartigen einrückungen zu lesen erschrickt mich jedesmal ;)

  • Naja, erst, wenn sich die Werte der Sensoren ändern, wird alles aktiv... Habe da leider keine Ahnung von, die Werte ändern sich bei der Genauigkeit sekündlich...

    Mir ist das Thema Threading nicht geläufig... Ist es parallele Abarbeitung?

    Ich wollte das Script vorerst nur erweitern um:
    - automatisches Ausschalten des Displays zu bestimmter Uhrzeit (display off statt on begehlen, aber wie setzt man die Uhrzeit und wo?)
    - schreiben der Werte in eine CSV-Datei alle 10 Minuten

    Ich brauche diese CSV-Datei, da diese auf dem Raspi bereitgestellt werden soll für eine grafische Anzeige auf dem iPad... Die App dort wertet CSV aus.

    • Offizieller Beitrag

    Jupp Threading is paralle Abarbeitung. In Zeile 154wird die Funktion aufgerufen welche das Display beleuchtet. Um diese würde ich jetzt ne abfrage herumbauen ob die aktuelle systemzeit größer als meine Wunschzeit ist, wenn ja bleibt das das Display aus.

    Timestamps erzeugt man mit

    Code
    time_format = "%H:%M:%S"
    timestamp=time.strftime(time_format, time.localtime())


    Wunschzeit

    Code
    wunschausgehzeit = "22:00:00"
    wunschangehzeit = "07:00:00"

    Zeile 154

    Code
    if timestamp < wunschausgehzeit and timestamp > wunschangehzeit:
             self.lcd.backlight_on()

    Bei CSV müsste man die Werte vorher sicherheitshalber in ein dictionary schreiben. Dadurch, das das script eh alle 5min Datan ins inet sendet wäre dort der ideale Zeitpunkt um die Werte zu speichern.

    Gute Nacht

  • Klasse, und diese 6 Zeilen setzte ich in Zeile 154 ein?

    Aber in der letzten Zeile schaltet sich das Display ein, wo schaltet es sich aus?

    Und, wie leite ich die Ausgabe der Werte in eine CSV um alle 10 Minuten, wobei die Datei nicht unendlich gross werden darf...

    Das geht ja schon in eine super Richtung

    • Offizieller Beitrag

    Soweit wie ich verstehe, sollte es so nur anschalten wenn du innerhalb des Betriebzeitraumes bist:

    teste mal bitte ob das script so läuft oder ob er ne fehlermeldung schmeisst, er sollte in /home/pi ne datei anlegen und aller 5min (dann wenn er auch die Daten ins internet hochlädt) die Werte speichern
    Das attachment wieder in .py umbennen

  • Hi,

    Die Zeilen füge ich oben am Anfang ein, den vorherigen Code zur Beendigung in Zeile 154?

    Das Display leuchtet permanent, sobald es den on-Befehl erhält - auch, wenn das Skript nicht mehr läuft, leuchtet es. Daher muss man es vor Beendigung des Scripts wohl erst abschalten.

    Welchen Editor verwendest du ? Ich nutze derzeit nano per ssh. Suche noch einen Editor für den Mac, damit ich dann mit Programmierung loslegen kann, ein Buch suche ich für Python auch noch.

    Und, wie kann ich den CSV-Export realisieren?

    Einmal editiert, zuletzt von blebbens (9. Juni 2013 um 13:08)

    • Offizieller Beitrag

    in dem attachment ist alles drin, auch der csv export ;), weiss nur nicht obs fehlerfrei durchläuft, weil ich es nicht testen kann aufgrund fehlender hardware.
    Also einfach diese Version ausführen anstelle deine bisherigen DemoScriptes
    auf der console nutze ich vim, am rechner, pyscripter oder notepadd++.

    Das Openbook von Galileo ist für anfänger recht brauchbar.

  • Besten Dank. Ich teste es nachher, bin derzeit weit vom Raspi weg und auf dem Heimweg.

    Dann muss ich nur noch eine Idee finden, wie der Raspi diese Datei dann bereitstellt per Internet, damit das iPad von unterwegs drauf zugreifen kann.

  • Wollte die CSV eigentlich auf dem Raspi bereitstellen, aber eine Dropbox habe ich natürlich auch.

    Hm, die App Statusboard kann nicht auf Dropbox zugreifen. Reicht es, wenn ich die Datei ins Verzeichnis /etc/www schiebe? Am liebsten, dass diese dort gleich gespeichert wird?

    • Offizieller Beitrag

    ja du kannst die auch dort speichern, Zeile 58 definiert die Pfad. (weiss grad nicht ob der user pi dort überhaupt Datein erstellen darf, das is das problem wenn man immer root ist ;), aber das kriegst du ja schnell raus.alternativ kannst du versuchen nen symlink von /var/www auf ein anderes Verzeichnis zu machen.

  • root@raspberrypi:/home/pi# sudo python weather_xively_mod.py
    File "weather_xively_mod.py", line 54
    global csvdict
    ^
    IndentationError: expected an indented block

    Der Fehler wird gemeldet beim Ausführen des Scripts...

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!