Hallo zusammen,
mittlerweile habe ich es ja dank eurer Hilfe geschafft, diverse Sensorwerte abzugreifen und diese in einer while True Schleife fortlaufend auf einem LCD2004 auszugeben. Leider bricht dieses Skript aber immer nach etwa 4 Stunden ab... im Assistant steht "unused import datetime, unused pause imported from signal, unused argument signum und unused argument frame"...
Liegt das daran? Und wenn ja, wie kann man das umgehen?
Wäre euch über Tipps sehr dankbar
Skript bricht immer nach etwa 4 Stunden ab?!
Du darfst gerne deinen Code posten, aber es wäre gut, wenn du ihn vorher so verkleinerst, dass er bei uns läuft und auch immer noch den Fehler zeigt, aber möglichst wenig anderen Code enthält, der dafür nicht nötig ist.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Entschuldigung
Code: Alles auswählen
import urllib.request
import requests
import datetime
from signal import signal, SIGTERM, SIGHUP, pause
from rpi_lcd import LCD
from time import sleep
session = requests.Session()
response = session.post("https://server.growatt.com/login", data={
"account": "abc",
"password": "abc",
"validateCode": "",
"isReadPact": "0",
})
lcd = LCD()
def safe_exit(signum, frame):
exit(1)
try:
while True:
signal(SIGTERM, safe_exit)
signal(SIGHUP, safe_exit)
TempGartenhaus = 'http://192.168.178.22:8181/alchy.exe?sa ... 2).Value()'
FeuchtGartenhaus = 'http://192.168.178.22:8181/alchy.exe?sa ... 2).Value()'
with urllib.request.urlopen(TempGartenhaus) as f1:
g1 = (f1.read().decode('utf-8'))
h1 = (g1[g1.find("sagt")+5:g1.find("sagt")+9])+" Grad "
response = session.post("https://server.growatt.com/panel/getDevicesByPlantList", data={"currPage": "1","plantId": "abc"})
g = response.json()
response = session.post("https://server.growatt.com/panel/storag ... StatusData", data={"typ": "STORAGE", "plantId": "abc", "storageSn": "abc"})
l = response.json()
lcd.text(g.get('obj').get('datas')[0].get('lastUpdateTime'), 1)
lcd.text("PV " + l.get('obj').get('ppv1') + "W + Netz " + l.get('obj').get('gridPower') + "W", 2)
lcd.text("Bat " + l.get('obj').get('batPower') + "W + VB " + l.get('obj').get('loadPower') + "W", 3)
lcd.text("Batterie noch " + l.get('obj').get('capacity') + "%", 4)
sleep(10)
lcd.text("Gartenhaus", 1)
lcd.text(h1 + h2, 2)
sleep(3)
except KeyboardInterrupt:
pass
finally:
lcd.clear()
sorry, ich bereite das nochmal sauber auf...
darf ich fragen, wie man denn urllib.error.URLError: <urlopen error [Errno 101] Network is unreachable> umgeht?
denke das ist der Fehler, also quasi wenn er einen Netzwerkfehler hat / also quasi WLAN kurzfristig unterbrochen ist...
reicht es da, vor jedem url-Aufruf quasi ein "Try: " zu setzen?
darf ich fragen, wie man denn urllib.error.URLError: <urlopen error [Errno 101] Network is unreachable> umgeht?
denke das ist der Fehler, also quasi wenn er einen Netzwerkfehler hat / also quasi WLAN kurzfristig unterbrochen ist...
reicht es da, vor jedem url-Aufruf quasi ein "Try: " zu setzen?
Jein. Es muss schon etwas mehr sein, denn wenn etwas *nicht* geklappt hat, kann das Programm ja nicht weiter rechnen, weil es von den Ergebnissen abhaengt. Also muss man retries einplanen.
Alternativ kann der ganze Kram auch in eine systemd-Unit, damit er wieder gestartet wird, wenn er, aus welchen Gruenden auch immer, abbricht. Das ist im Zweifel stabile, weil deine Faehigkeiten, robust zu programmieren, wenig ausgepraegt sind. Und es einfach woanders krachen kann.
Alternativ kann der ganze Kram auch in eine systemd-Unit, damit er wieder gestartet wird, wenn er, aus welchen Gruenden auch immer, abbricht. Das ist im Zweifel stabile, weil deine Faehigkeiten, robust zu programmieren, wenig ausgepraegt sind. Und es einfach woanders krachen kann.
Da muss nichts geaendert werden. Du musst gegebene Stichworte mal suchen, um eine Idee zu bekommen, was die bedeuten, und es dann probieren. Und dich natuerlich auch melden, wenn's nicht geht, oder du Fragen hast. Aber Kiefer auf, Kiefer zu, und schlucken - das sind schon deine Aufgaben, ich bin nicht deine Vogelmutti, die dir alles vorkaut.
Auch mit Einrückungen wäre der Code nicht lesbar.
Man benutzt keine einbuchstabigen Variablennamen. Was soll gl, hl, g oder l denn bedeuten? Was ist ein temporäres Gartenhaus?
Warum verwendest Du mal requests und dann auch urllib?
Warum denkst Du, dass Du einen eigenen signal-Handler brauchst?
Mit find und Indexgahampel geht man normalerweise nicht auf Text los. Wie sieht denn die Rückgabe der Gartenhaus-URL aus?
Man hat nicht irgendwo im Code literale Strings mit IDs oder Passwörtern, sondern definiert die als Konstanten am Anfang des Programms, um sie leicht finden zu können.
Auf Werte in Wörterbüchern greift man über Eckige Klammern zu, nicht per get.
Man benutzt keine einbuchstabigen Variablennamen. Was soll gl, hl, g oder l denn bedeuten? Was ist ein temporäres Gartenhaus?
Warum verwendest Du mal requests und dann auch urllib?
Warum denkst Du, dass Du einen eigenen signal-Handler brauchst?
Mit find und Indexgahampel geht man normalerweise nicht auf Text los. Wie sieht denn die Rückgabe der Gartenhaus-URL aus?
Man hat nicht irgendwo im Code literale Strings mit IDs oder Passwörtern, sondern definiert die als Konstanten am Anfang des Programms, um sie leicht finden zu können.
Auf Werte in Wörterbüchern greift man über Eckige Klammern zu, nicht per get.
Code: Alles auswählen
import requests
from time import sleep
from rpi_lcd import LCD
ACCOUNT = "abc"
PASSWORD = "abc"
PLANT_ID = "abc"
STORAGE_SN = "abc"
URL_GOWATT = "https://server.growatt.com"
URL_GOWATT_PLANT_LIST = URL_GOWATT + "/panel/getDevicesByPlantList"
URL_GOWATT_STORAGE_STATUS = URL_GOWATT + "/panel/storag ... StatusData"
URL_TEMPERATURE_SUMMER_HOUSE = 'http://192.168.178.22:8181/alchy.exe?sa ... 2).Value()'
URL_HUMIDITY_SUMMER_HOUSE = 'http://192.168.178.22:8181/alchy.exe?sa ... 2).Value()'
def main_loop(session, lcd):
while True:
response = session.get(URL_TEMPERATURE_SUMMER_HOUSE):
_, _, text = response.content.partition("sagt")
temperature_summer_house = text.split()[0]
response = session.post(URL_GOWATT_PLANT_LIST, data={"currPage": "1","plantId": PLANT_ID})
plant_list = response.json()
plant = plant_list['obj']['datas'][0]
response = session.post(URL_GOWATT_STORAGE_STATUS, data={"typ": "STORAGE", "plantId": PLANT_ID, "storageSn": STORAGE_SN})
data = response.json()['obj']
lcd.text(plant['lastUpdateTime'], 1)
lcd.text(f"PV {data['ppvl']}W + Netz {data['gridPower']}W", 2)
lcd.text(f"Bat {data['batPower']}W + VB {data['loadPower']}W", 3)
lcd.text(f"Batterie noch {data['capacity']}%", 4)
sleep(10)
lcd.text("Gartenhaus", 1)
lcd.text(f"{temperature_summer_house} Grad", 2)
sleep(3)
def main():
session = requests.Session()
response = session.post(URL_GOWATT + "/login", data={
"account": ACCOUNT,
"password": PASSWORD,
"validateCode": "",
"isReadPact": "0",
})
lcd = LCD()
try:
main_loop(session, lcd)
except KeyboardInterrupt:
pass
finally:
lcd.clear()
if __name__ == "__main__":
main()
- __blackjack__
- User
- Beiträge: 13938
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Chrissili: Egal wie die tatsächliche Einrückung aussieht: Da wird ein `h2` benutzt das nirgends definiert wird, also ist das sicher nicht der Code der da tatsächlich läuft.
`datetime` und `pause` werden importiert, aber nirgends verwendet. Das mit dem `signal()`-Modul ist aber auch unsinnig. An sich schon, aber in jedem Schleifendurchlauf immer wieder die gleiche Funktion zu registrieren kommt da noch mal oben drauf.
`FeuchtGartenhaus` wird definiert, aber nirgends verwendet.
Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
`requests.Session`-Objekte sind Kontextmanager. Die sollte man mit ``with`` verwenden, wo das geht.
Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).
Namen sollten keine kryptischen Abkürzungen enthalten oder gar nur daraus bestehen. Der Name soll dem Leser verraten was der Wert dahinter bedeutet. Einbuchstabige Namen sind nur selten sinnvolle Namen. Und man nummeriert keine Namen.
Im gleichen Programm mal `urllib.request` und mal `requests` zu verwenden macht wenig Sinn.
`str.find()` hat das Problem, dass es *immer* eine Zahl liefert, die als Index verwendet werden kann, auch in dem Fall wenn die Teilzeichenkette gar nicht gefunden wird. Dann macht das Programm etwas sehr wahrscheinlich nicht sinnvolles. Darum ist es besser `str.index()` zu verwenden, was den Fehler nicht so einfach unbemerkt durchrutschen lässt.
Die meisten `get()`-Aufrufe auf Wörterbüchern in dem Code machen keinen Sinn. Zum einen wird ``.get("obj")`` verdammt oft wiederholt, zum anderen kann man damit zwar einen `KeyError` vermeiden, in sehr vielen Fällen wird dann aber vom `None` wieder versucht etwas mit `get()` abzufragen, womit man den Fehler einfach nur verschoben hat.
Ungetestet:
Wobei das für meinen Geschmack schon zu viel Code in der einen Funktion ist. Und wenn da jetzt auch noch mehr Fehlerbehandlung dazu kommt, gibt es noch tiefere Einrückung und es wird dann langsam unübersichtlich.
`datetime` und `pause` werden importiert, aber nirgends verwendet. Das mit dem `signal()`-Modul ist aber auch unsinnig. An sich schon, aber in jedem Schleifendurchlauf immer wieder die gleiche Funktion zu registrieren kommt da noch mal oben drauf.
`FeuchtGartenhaus` wird definiert, aber nirgends verwendet.
Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
`requests.Session`-Objekte sind Kontextmanager. Die sollte man mit ``with`` verwenden, wo das geht.
Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).
Namen sollten keine kryptischen Abkürzungen enthalten oder gar nur daraus bestehen. Der Name soll dem Leser verraten was der Wert dahinter bedeutet. Einbuchstabige Namen sind nur selten sinnvolle Namen. Und man nummeriert keine Namen.
Im gleichen Programm mal `urllib.request` und mal `requests` zu verwenden macht wenig Sinn.
`str.find()` hat das Problem, dass es *immer* eine Zahl liefert, die als Index verwendet werden kann, auch in dem Fall wenn die Teilzeichenkette gar nicht gefunden wird. Dann macht das Programm etwas sehr wahrscheinlich nicht sinnvolles. Darum ist es besser `str.index()` zu verwenden, was den Fehler nicht so einfach unbemerkt durchrutschen lässt.
Die meisten `get()`-Aufrufe auf Wörterbüchern in dem Code machen keinen Sinn. Zum einen wird ``.get("obj")`` verdammt oft wiederholt, zum anderen kann man damit zwar einen `KeyError` vermeiden, in sehr vielen Fällen wird dann aber vom `None` wieder versucht etwas mit `get()` abzufragen, womit man den Fehler einfach nur verschoben hat.
Ungetestet:
Code: Alles auswählen
#!/usr/bin/env python3
from time import sleep
import requests
from rpi_lcd import LCD
def main():
try:
with requests.Session() as session:
session.post(
"https://server.growatt.com/login",
data={
"account": "abc",
"password": "abc",
"validateCode": "",
"isReadPact": "0",
},
)
lcd = LCD()
while True:
response_text = session.get(
"http://192.168.178.22:8181/alchy.exe?sa ... 2).Value()"
).text
index = response_text.index("sagt")
temperature_text = (
response_text[index + 5 : index + 9] + " Grad"
)
devices_data = session.post(
"https://server.growatt.com/panel/getDevicesByPlantList",
data={"currPage": "1", "plantId": "abc"},
).json()["obj"]
status_data = session.post(
"https://server.growatt.com/panel/storag ... StatusData",
data={
"typ": "STORAGE",
"plantId": "abc",
"storageSn": "abc",
},
).json()["obj"]
lcd.text(devices_data["datas"][0]["lastUpdateTime"], 1)
lcd.text(
f"PV {status_data['ppv1']}W + Netz {status_data['gridPower']}W",
2,
)
lcd.text(
f"Bat {status_data['batPower']}W + VB {status_data['loadPower']}W",
3,
)
lcd.text(f"Batterie noch {status_data['capacity']}%", 4)
sleep(10)
lcd.text("Gartenhaus", 1)
lcd.text(f"{temperature_text} {h2}", 2)
sleep(3)
except KeyboardInterrupt:
pass
finally:
lcd.clear()
if __name__ == "__main__":
main()
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
— Scott Bellware
Hallo,
vielleicht so, wie du es mit 'KeyboardInterrupt' machst:
https://requests.readthedocs.io/en/late ... exceptions
Grüße
Dennis
vielleicht so, wie du es mit 'KeyboardInterrupt' machst:
https://requests.readthedocs.io/en/late ... exceptions
Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
- DeaD_EyE
- User
- Beiträge: 1206
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
So z.B.:
Grundsätzlich sollte man auch bei der Abfrage bzw. beim Post-Request auch einen Timeout setzen, damit er bei Nichterreichbarkeit im Programm weiter macht und nicht unendlich lange wartet.
Code: Alles auswählen
import time
import requests
OK = "https://google.de" # Verbindung ist möglich
NOK = "https://0.0.0.0" # Nullroute, keine Verbindung
while True:
time.sleep(1)
try:
response = requests.post(NOK)
except requests.ConnectionError:
print("Netzwerkproblem...")
continue
print(
"Dieser Code wird bei einem Fehler nicht ausgeführt, da zuvor `continue` verwendet worden ist."
)
Code: Alles auswählen
import time
import logging
import requests
OK = "https://google.de" # Verbindung ist möglich
logging.basicConfig(format="%(asctime)s %(name)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
while True:
time.sleep(1)
try:
# hier ist nun ein Timeout gesetzt
# wenn der Verbindungsaufbau und die Abfrage länger dauert,
# dann wird auch ein ConnectionError ausgelöst,
# den man abfangen muss
response = requests.post(OK, timeout=0.001)
# 1 ms, so schnell antwortet kein realer Server
except requests.ConnectionError:
# mit Logging ist besser
logger.warning("Keine Netzwerkverbindung")
continue
print(
"Dieser Code wird bei einem Fehler nicht ausgeführt, da zuvor `continue` verwendet worden ist."
)
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server