Variablen machen komische Sachen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
8023
User
Beiträge: 10
Registriert: Sonntag 21. Juli 2019, 15:21

Ich versuche den Leistungsbedarf und die Temperatur zu erfassen

Code: Alles auswählen

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

import re, os, rrdtool, time

# ds20b18
def read_sensor(path):
  value = "U"
  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), e:
    print time.strftime("%x %X"), "Error reading", path, ": ", e
  return value

data = 'N'
data += ':'
data += read_sensor("/sys/bus/w1/devices/28-00044a52d2ff/w1_slave")
data += ':'
data += str(os.system("shelly.sh"))


# insert data into round-robin-database
# rrdtool.update("/home/pi/bosch.rrd",data)

print "bosch.rrd: ", data
Das mit der Temperatur und der Leistung funktioniert, aber beim Zusammenklöppeln stimmt irgendwas nicht:

Code: Alles auswählen

pi@Raspi-B:~ $ ./getbosch.py
42.57
bosch.rrd:  N:26.437:0
pi@Raspi-B:~ $ 
Ich hätte erwartet, dass N:26.437:42.57 ausgegeben wird und nicht ...:0 . Also wo zum Geier kommt die 0 her?
Ich versteh es nicht :roll: Jemand eine Idee?



PS:
shelly.sh gibt nur die Leistung zurück

Code: Alles auswählen

pi@Raspi-B:~ $ shelly.sh
42.51
pi@Raspi-B:~ $
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ein Blick in die Dokumentation von os.system bringt Erleuchtung. Und da steht auch was man stattdessen benutzen soll.
8023
User
Beiträge: 10
Registriert: Sonntag 21. Juli 2019, 15:21

Danke, alles klar.
Benutzeravatar
__blackjack__
User
Beiträge: 14045
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@8023: Noch ein paar Anmerkungen zum Quelltext:

Python 2 ist am Ende, das sollte man nicht mehr verwenden, insbesondere nicht für neue Projekte: https://pythonclock.org/

Eingerückt wird vier Leerzeichen pro Ebene.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Importe von mehreren Modulen kommen üblicherweise in separate Zeilen und wenn man Importe nach ”Quelle” gruppiert, sieht man leichter was aus der Standardbibliothek, was aus externen Bibliotheken, und was aus dem eigenen Projekt kommt.

Die `read_sensor()`-Funktion sollte sich weder um die Umwandlung in eine Zeichenkette noch um die Ausgabe einer Fehlermeldung kümmern. Da sind beides Aufgaben des Aufrufers.

Die Ausgabe könnte man per `logging` machen, denn dann hätte der Aufrufer die Chance sie zu unterdrücken und/oder zu entscheiden wie und wo sie erfolgen soll.

Dateien sollte man wo möglich zusammen mit der ``with``-Anweisung öffnen um das schliessen auch ohne ``try``/``finally`` sicherzustellen.

Bei Textdateien sollte man immer explizit eine Kodierung angeben.

Die `readline()`-Methode von Dateien braucht man nur sehr selten tatsächlich und sie ist ineffizienter als das Dateiobjekt als Iterator über Zeilen zu verwenden.

Pfade/Dateinamen und die regulären Ausdrücke würde ich als Konstanten herausziehen.

Einbuchstabe Namen sind nur sehr selten gute Namen. `file` und `match` sollte man ausschreiben.

Zusammenstückeln von Werten und Zeichenkettenliteralen per `str()` und ``+`` ist eher BASIC als Python. Wiederholtes ``+=`` ist zudem ineffizient weil Zeichenketten unveränderbar sind, und dadruch jedes mal mehr Daten in eine neue Zeichenkette kopiert werden müssen. In Python gibt es für so etwas Zeichenkettenformatierung mit der `format()`-Methode und ab Python 3.6 f-Zeichenkettenliterale.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import logging
import re
import subprocess

import rrdtool

LOGGER = logging.Logger(__name__)

SENSOR_FILENAME = '/sys/bus/w1/devices/28-00044a52d2ff/w1_slave'
RRD_FILENAME = '/home/pi/bosch.rrd'
SHELLY_FILENAME = 'shelly.sh'

HEX_VALUE_PATTERN = '(?:[0-9a-f]{2} ){9}'
CRC_RE = re.compile(HEX_VALUE_PATTERN + ': crc=[0-9a-f]{2} YES')
VALUE_RE = re.compile(HEX_VALUE_PATTERN + 't=(?P<value>[+-]?[0-9]+)')


def read_sensor(path):
    try:
        with open(path, 'r', encoding='ASCII') as lines:
            if CRC_RE.match(next(lines)):
                match = VALUE_RE.match(next(lines))
                if match:
                    return int(match.group('value')) / 1000
    except IOError:
        LOGGER.exception('Error reading %s', path)
    
    return None


def main():
    value = read_sensor(SENSOR_FILENAME)
    shelly_result = subprocess.run(
        SHELLY_FILENAME,
        check=True,
        stdout=subprocess.PIPE,
        universal_newlines=True,
    )
    data = f'N:{"U" if value is None else value}:{shelly_result.stdout}'
    rrdtool.update(RRD_FILENAME, data)
    print('RRD data:', data)


if __name__ == '__main__':
    main()
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
8023
User
Beiträge: 10
Registriert: Sonntag 21. Juli 2019, 15:21

Hey danke für deine Mühe, aber die Sache ist die; Der Code ist nicht auf meinem Mist gewachsen... (Und python ist sowieso nicht meins ;) ), von mir ist nur die Leistungsabfrage aus das shelly.

aber Danke...
8023
User
Beiträge: 10
Registriert: Sonntag 21. Juli 2019, 15:21

@__blackjack__ ich habe deine Version mal ausprobiert...
aber ich laufe in ein

Code: Alles auswählen

pi@Raspi-B:~ $ getbosch.py
RRD data: N:29.125:41.12

Traceback (most recent call last):
  File "/usr/bin/getbosch.py", line 51, in <module>
    main()
  File "/usr/bin/getbosch.py", line 45, in main
    rrdtool.update(RRD_FILENAME, data)
rrdtool.OperationalError: /home/pi/bosch.rrd: Function update_pdp_prep, case DST_GAUGE - Converted '41.02
' to 41.020000, but cannot convert '
'
das hatte ich bei meine Version auch, aber hab das glaub ich mit

Code: Alles auswählen

f = subprocess.check_output("shelly.sh")
    if f:
        value = str(float(f))
hingefrickelt bekommen. Jetzt weiß ich aber nicht so recht wo ich ansetzten soll..?

..und ja, ich hab keine Ahnung :D

Code: Alles auswählen

#!/usr/bin/env python3

import logging
import re
import subprocess
import time

import rrdtool

LOGGER = logging.Logger(__name__)

SENSOR_FILENAME = '/sys/bus/w1/devices/28-00044a52d2ff/w1_slave'
RRD_FILENAME = '/home/pi/bosch.rrd'
SHELLY_FILENAME = 'shelly.sh'

HEX_VALUE_PATTERN = '(?:[0-9a-f]{2} ){9}'
CRC_RE = re.compile(HEX_VALUE_PATTERN + ': crc=[0-9a-f]{2} YES')
VALUE_RE = re.compile(HEX_VALUE_PATTERN + 't=(?P<value>[+-]?[0-9]+)')


def read_sensor(path):
    try:
        with open(path, 'r', encoding='ASCII') as lines:
            if CRC_RE.match(next(lines)):
                match = VALUE_RE.match(next(lines))
                if match:
                    return int(match.group('value')) / 1000
    except IOError:
        LOGGER.exception('Error reading %s', path)

    return None


def main():
    while 1:
        value = read_sensor(SENSOR_FILENAME)
        shelly_result = subprocess.run(
            SHELLY_FILENAME,
            check=True,
            stdout=subprocess.PIPE,
            universal_newlines=True,
        )
        data = f'N:{"U" if value is None else value}:{shelly_result.stdout}'
        rrdtool.update(RRD_FILENAME, data)
        print('RRD data:', data)
        time.sleep(10)


if __name__ == '__main__':
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 14045
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ah, `rrdtool` mag das Zeilenende nicht, welches von Shell-Skript ausgegeben wird. Das wird man mit der `rstrip()`-Methode los.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
8023
User
Beiträge: 10
Registriert: Sonntag 21. Juli 2019, 15:21

danke...!
Antworten