Zwischenzeitlich läuft mein Projekt recht gut auch Danke der Hilfe in diesem Thread:
http://www.python-forum.de/viewtopic.php?t=33895
Die bisherige Version wird als Python Funktion per Konsole gestartet und gibt den jeweiligen Status der Daten auch auf der Konsole aus.
Das soll auch so bleiben. Allerdings möchte ich einen Zugang per Browser/Mobilem Gerät haben.
Mir scheint http://webpy.org/ ist ein geeignetes Tool hierfür.
Mein Problem, zwar kann ich 'web' einbinden, aber eine entsprechende class hat keinen Zugriff auf die Parameter der eigentlichen Anwendung. (Es wird / und soll keine Datenbank verwendet werden).
Welche Beschreibung ist notwendig, damit ihr mir auf die Sprünge helfen könnt?
(... und bitte keine Häme von wegen globale Parameter)
py Project mit web.py
@gNeandr: diese Url- und Klassendefinitionen von webpy sehen mir etwas verworren aus. Ich würde Dir flask oder bottle empfehlen.
Dein Problem verstehe ich nicht ganz. Wenn ein Skript hast, das Deine Methoden per Konsole zugänglich macht, mußt Du doch einfach nur diese Aufrufe über Urls verfügbar machen. Also wenn das Konsolen-Skript Zugriff hat, warum dann das Web-Interface nicht?
Dein Problem verstehe ich nicht ganz. Wenn ein Skript hast, das Deine Methoden per Konsole zugänglich macht, mußt Du doch einfach nur diese Aufrufe über Urls verfügbar machen. Also wenn das Konsolen-Skript Zugriff hat, warum dann das Web-Interface nicht?
Zu web.py etc .. web.py schien mir recht plausibel und einfach, wohl deshalb habe ich mir flask und bottle nicht angesehen .. werd's nachholen.Sirius3 hat geschrieben:@gNeandr: diese Url- und Klassendefinitionen von webpy sehen mir etwas verworren aus. Ich würde Dir flask oder bottle empfehlen.
Dein Problem verstehe ich nicht ganz. Wenn ein Skript hast, das Deine Methoden per Konsole zugänglich macht, mußt Du doch einfach nur diese Aufrufe über Urls verfügbar machen. Also wenn das Konsolen-Skript Zugriff hat, warum dann das Web-Interface nicht?
Mein Skript enthält einen Hauptthread und zwei weitere jobs, die
1\ die Daten erzeugen/auf der Konsole ausgeben (mittels Threads und event handling zur Beendigung)
2\ auf weitere Befehlsdaten (derzeit) über Konsoleeingaben mittels eines anderen Skripts warten (Listener)
Das Web-Interface soll auf die mittels 1\ erzeugten Daten zugreifen und anzeigen
Hier die Struktur meines Skripts mit dem derzeitigen web.py Ansatz ... der leider insofern nicht funktioniert, als ich keinen Zugriff auf die Daten jobs = [] # store scheduled tasks bekomme:
Mit der class index soll der aktuelle Stand von 'jobs' an die web-Seite übergeben werden. Siehe Zeile 45. Das klappt nicht.
Es werden nur Daten im Zustand vor dem Aufruf von app.run() angezeigt .. nicht was notwendig ist.
FMPOV ist es kein Problem von web.py mit app.run() sondern es liegt an der Gesamtstruktur. But here I'm struggeling
Code: Alles auswählen
#!/usr/bin/env python
# import part
# globals
__version__ = '0.1g'
sched = BackgroundScheduler()
jobs = [] # store scheduled tasks
def jobs_listing(exit_event, name, calling):
try:
while not exit_event.is_set(): # loop to keep scheduler alive
updateJobsListing() # updating 'jobs', ..
sleep(10) # this runs every 10 sec
finally:
print (' piScheduler - Exit >{0}<'.format(name))
def job_serve(exit_event, name):
try:
while True:
# doing stuff and
# waiting for condition to leave try using 'break'
break
except:
pass
finally:
# closing part
exit_event.set()
listener.close()
sched.shutdown()
sys.exit(0)
# for web.py
urls = (
'/', 'index'
)
# for web.py
class index:
def GET(self, globals()):
x = ("hello this is RPI on .16\n")
x1 = __version__ + " " + str(datetime.datetime.now())[:19]
# >>>>>> no access to changed values like 'jobs' <<<<<<
return x + x1
def main():
# initializing with parameter
sched.start() # start the scheduler
exit_event = Event() # define an event to allow keyboard interrupt and other
Thread(target=jobs_listing, args=(exit_event, 'pilight Jobs', calling)).start()
# use web.py to get the scheduler data on a web page
app = web.application(urls, globals())
app.run()
# a routine to read the schedule data, update 'jobs'
# and kick the RPI functions
job_serve(exit_event, 'piScheduler')
# close down after exit_event was set true
sched.shutdown()
exit()
#---------------------------------
if __name__ == "__main__":
main()
Es werden nur Daten im Zustand vor dem Aufruf von app.run() angezeigt .. nicht was notwendig ist.
FMPOV ist es kein Problem von web.py mit app.run() sondern es liegt an der Gesamtstruktur. But here I'm struggeling
@gNeandr: Natürlich liegt das an `app.run()` das Du nur Zustände hast die davor gesetzt wurden, denn ein *danach* gibt's nicht. Der `run()`-Aufruf kehrt nicht zurück, der `job_server()`-Aufruf wird nie ausgeführt.
@BlackJack
Ja, so ist es .. und ein Test print Befehl zeigt es ja auch ganz klar .. klar wie Kloßbrühe
D.h hier sollte ich wohl einen zusätzlichen Thread haben und dort app.run() laufen lassen,
oder gibt's 'n andere / bessere Möglichkeit?
(Wie gesagt die web.py Eigenschaften oder deren Alternativen mal außen vor gelassen)
Ja, so ist es .. und ein Test print Befehl zeigt es ja auch ganz klar .. klar wie Kloßbrühe
D.h hier sollte ich wohl einen zusätzlichen Thread haben und dort app.run() laufen lassen,
oder gibt's 'n andere / bessere Möglichkeit?
(Wie gesagt die web.py Eigenschaften oder deren Alternativen mal außen vor gelassen)
Zurück auf null .. bzw zu deiner/dieser Frage, wahrscheinlich ist das der richtigere Weg! Zumal ich die Kommunikation mit einem zweiten Skript genauso mache. In meinem Post des Codes habe ich die Details von 'job_serve' ausgelassen. Da stehtSirius3 hat geschrieben: Dein Problem verstehe ich nicht ganz. Wenn ein Skript hast, das Deine Methoden per Konsole zugänglich macht, mußt Du doch einfach nur diese Aufrufe über Urls verfügbar machen. Also wenn das Konsolen-Skript Zugriff hat, warum dann das Web-Interface nicht?
Code: Alles auswählen
def job_serve(exit_event, name):
address = (192.168.178.xxx, 6001)
# listener = Listener(address, authkey='secret password')
listener = Listener(address')
try:
while True:
connection = listener.accept()
print (name, str(connection))
message = connection.recv().strip() <<<<<< error line
#
# process the incoming message...
#
print (' .... incoming msg: ', message)
except:
pass
finally:
# abgesang
Code: Alles auswählen
address = (server, port)
conn = Client(address)
conn.send(message)
Allerdings verstehe ich nicht, wie ich per URL entsprechende Befehle absetzen kann, zB. '192.168.178.xxx:6001' gibt NUR einen Memory Fehler:
Code: Alles auswählen
xSchedule <read-write Connection, handle 6>
Traceback (most recent call last):
File "xSchedule.py", line 572, in <module>
main()
File "xSchedule.py", line 564, in main
job_serve(exit_event, 'xSchedule')
File "xSchedule.py", line 446, in job_serve
message = connection.recv().strip()
MemoryError
Was ist zu tun, um per Web Befehl zu arbeiten?
@gNeandr: Vielleicht liegt's ja nur an mir oder an der vorgerückten Stunde, aber ich habe irgendwie keinen Überblick was da so gemacht wird und es sieht sehr komplex aus. Ein `MemoryError` bei einem `recv()` auf einem Socket (?) sieht komisch aus. Wobei man das eigentlich gar nicht ohne Argument aufrufen können dürfte‽
@gNeandr: was hat connection für einen Typ? Und was ist ein Listener? Ein nacktes except das jede Exception einfach so ignoriert, ist immer schlecht. Woher hast Du dann überhaupt die Fehlermeldung?
Um Befehle zu verarbeiten verwende ich immer einen ganz normalen Web-Server, der per json kodierte Nachrichten bekommt und sendet. Da Du sowieso schon einen laufen hast, kannst Du den gleich mitbenutzen.
Um Befehle zu verarbeiten verwende ich immer einen ganz normalen Web-Server, der per json kodierte Nachrichten bekommt und sendet. Da Du sowieso schon einen laufen hast, kannst Du den gleich mitbenutzen.
@Sirius und @BlackJack und @Leonidas
Meine "Lösung" geht zurück auf einen Beitrag, den wir im Frühjahr diskutiert haben, siehe hier:
http://www.python-forum.de/posting.php? ... 1&p=258055
und wie gesagt, das läuft zur Zufriedenheit.
Es geht jetzt darum nicht nur Befehle zu übergeben wie mit einem separaten Script ala:Im Codeteil des og. Posts ist ab Zeile 21 'def server(..)' die das skizzierte Clientscript bedient.
Ich sollte doch diesen Teil nutzen können, um auch Aufrufe über eine Web-Seite zu bedienen. Allerdings tue ich mich da schwer.
Die Memory Err Meldung würde entsprechen dem zitierten Code an Zeile 27 kommen.
Meine "Lösung" geht zurück auf einen Beitrag, den wir im Frühjahr diskutiert haben, siehe hier:
http://www.python-forum.de/posting.php? ... 1&p=258055
und wie gesagt, das läuft zur Zufriedenheit.
Es geht jetzt darum nicht nur Befehle zu übergeben wie mit einem separaten Script ala:
Code: Alles auswählen
if len(sys.argv) == 2:
message = sys.argv[1]
else:
message = 'pyClient : ' + str(datetime.datetime.now())
address = (server, 6001)
conn = Client(address, authkey='secret password')
conn.send(message)
conn.close()
Ich sollte doch diesen Teil nutzen können, um auch Aufrufe über eine Web-Seite zu bedienen. Allerdings tue ich mich da schwer.
Die Memory Err Meldung würde entsprechen dem zitierten Code an Zeile 27 kommen.
@gNeandr: Wenn das an der Stelle einen `MemoryError` gibt versuchst Du entweder deutlich zu viele Daten zu empfangen, was aber unwahrscheinlich ist wenn man sich den Kommandozeilenclient anschaut, oder Du hast anderweitig ein Speicherleck und an der Stelle ist dann die Message einfach zu viel.
Wenn Dein Hauptprogramm sowieso auf einem Port oder einer Pipe auf Nachrichten lauscht, sollte es doch eigentlich trivial sein dem mit einer *externen* Webanwendung Nachrichten zukommen zu lassen. Ich würde dann nicht versuchen den Webserver mit in das Hauptprogramm zu basteln. Du kannst dann natürlich nicht direkt auf irgendwelche Interna vom Hauptprogramm zugreifen, aber das wäre IMHO sowieso ein wenig unsauber. Dafür könnte man Nachrichten und Antworten programmieren um diese Informationen abzufragen. Das könnte man dann auch von dem Kommandozeilenclient aus benutzen.
Wenn Dein Hauptprogramm sowieso auf einem Port oder einer Pipe auf Nachrichten lauscht, sollte es doch eigentlich trivial sein dem mit einer *externen* Webanwendung Nachrichten zukommen zu lassen. Ich würde dann nicht versuchen den Webserver mit in das Hauptprogramm zu basteln. Du kannst dann natürlich nicht direkt auf irgendwelche Interna vom Hauptprogramm zugreifen, aber das wäre IMHO sowieso ein wenig unsauber. Dafür könnte man Nachrichten und Antworten programmieren um diese Informationen abzufragen. Das könnte man dann auch von dem Kommandozeilenclient aus benutzen.
@BlackJack Ja, den bestehenden Client zu nutzen (oder einen weiteren mit gleichartigem Code), daran hatte ich auch schon gedacht. Allerdings bin ich mir immer noch unsicher (siehe Mai Beiträge) wie das aufzubauen ist. Auf der Web-Seite brauchst dann wohl sowas wie ein Javascript Teil?
Ggf. hast du hierzu Pointer zum Nachlesen .. oder Beispiele? (Immer noch Neuling )
Bzgl. eines ev. MemeoryLeaks .. wie kann ich das finden/reparieren?
Ggf. hast du hierzu Pointer zum Nachlesen .. oder Beispiele? (Immer noch Neuling )
Bzgl. eines ev. MemeoryLeaks .. wie kann ich das finden/reparieren?
@gNeandr: Das würde mit einer Webanwendung im Grunde genau so aussehen, nur dass die `message` dann nicht von der Kommandozeile kommt, sondern über den Browser eingegeben wird. Also so grob skizziert mittels `bottle`:
Die URL muss man per POST-Anfrage aufrufen und dort ein Parameter `message` mitgeben — das kann zum Beispiel aus einem <form> kommen — und man bekommt als Antwort ein leeres JSON-Objekt geliefert. Das heisst das eignet sich eher für Anfragen via Javascript, statt diese URL direkt als `action`-Attribut im <form> zu hinterlegen. *Dafür* wäre es besser wenn die Funktion mit einer HTML-Seite antworten würde, denn die meisten Benutzer können mit JSON-Antworten nicht viel anfangen.
Speicherlecks kann man versuchen mit einem Profiler aufzuspüren.
Die Fehlermeldung an der Stelle kommt mir allerdings komisch vor. Die würde da zum Beispiel kommen können wenn man ein DVD-Image oder etwas vergleichbar grosses über das `Connection`-Objekt versendet.
Code: Alles auswählen
@route('/send_message', method='POST')
def send_message():
message = request.params['message']
if not message:
message = 'pyClient : {0}'.format(datetime.datetime.now())
address = (server, 6001)
conn = Client(address, authkey='secret password')
conn.send(message)
conn.close()
return {}
Speicherlecks kann man versuchen mit einem Profiler aufzuspüren.
Die Fehlermeldung an der Stelle kommt mir allerdings komisch vor. Die würde da zum Beispiel kommen können wenn man ein DVD-Image oder etwas vergleichbar grosses über das `Connection`-Objekt versendet.
@BlackJack
Danke für den web-Vorschlag, werd das mir mal später zu Gemüte führen.
Bzgl. MemoryError: Habe den RPI neu gestartet zumal ich etliche unsaubere Abbrüche hatte. Aber das hat nix gebracht (wahrscheinlich nicht überraschend )
Profiler == valgrind
... oder was empfiehlst du?
Danke für den web-Vorschlag, werd das mir mal später zu Gemüte führen.
Bzgl. MemoryError: Habe den RPI neu gestartet zumal ich etliche unsaubere Abbrüche hatte. Aber das hat nix gebracht (wahrscheinlich nicht überraschend )
Profiler == valgrind
... oder was empfiehlst du?
@gNeandr: Nein ich meinte eher einen der Python kennt. Also zum Beispiel das `memory_profiler`-Modul aus dem Package-Index.
@BlackJack: Danke für den obigen Vorschlag:
... skizziert mittels `bottle`:Das klappt keine Frage, habe es auch mit conn.recv() erweitert und bekomme auch "einfache" Strings zurück.
Allerdings scheitere ich im Moment daran ein JSON zu übertragen.
Als Rückmeldung wandle ich JSON Daten mittels str(..) um was dann kein Problem beim Senden macht. Aber auf der Empfangsseite sollte ich wieder aus dem String JSON Daten machen, um damit vernünftig zu arbeiten.
Kannst mir da Hinwesie geben .. vllt. ist ja der Ansatz aus JSON mittels str(..) die Übertragung zu machen schon "schief"
... skizziert mittels `bottle`:
Code: Alles auswählen
@route('/send_message', method='POST')
def send_message():
message = request.params['message']
if not message:
message = 'pyClient : {0}'.format(datetime.datetime.now())
address = (server, 6001)
conn = Client(address, authkey='secret password')
conn.send(message)
conn.close()
return {}
Allerdings scheitere ich im Moment daran ein JSON zu übertragen.
Als Rückmeldung wandle ich JSON Daten mittels str(..) um was dann kein Problem beim Senden macht. Aber auf der Empfangsseite sollte ich wieder aus dem String JSON Daten machen, um damit vernünftig zu arbeiten.
Kannst mir da Hinwesie geben .. vllt. ist ja der Ansatz aus JSON mittels str(..) die Übertragung zu machen schon "schief"
Python hat ein json-Modul, das nimmt dir die ganze Arbeit ab. In diesem Fall brauchst du die loads- und die dumps-Methoden. Letztere solltest du, statt deines str-Aufrufs, zur Umwandlung in einen json-String verwenden.
Das Leben ist wie ein Tennisball.
Wobei ich vorher schauen würde was das Webrahmenwerk bietet. Bottle macht das zum Beispiel automatisch wenn der Rückgabewert ein `dict` ist. Dann muss man sich eventuell auch nicht um so etwas wie die HTTP-Header kümmern die sagen das es sich um JSON und nicht um HTML handelt.