Seite 1 von 1

Anleitung: Drucker per websocket ansteuern

Verfasst: Di 31. Mai 2016, 21:53
von T1230
Guten Abend,

damit ich auch mal was für die Gemeinde hier tun kann, stell ich mal meinen python Code zur Verfügung, mit dem man den Repetier Server per websocket ansprechen kann. So kann man z.b.: wenn man sich ein Touch Interface geschrieben hat, häufig benutze Befehle per One-Klick ausführen.
In meinem Fall setze ich immer als erstes beim starten meiner Druckanlage immer gleich das Druckbett auf 50grad, sodass das Bett gleich Betriebsbereit ist. Man kann aber mit diesem Grundgerüst praktisch jeden G-Code an den Drucker senden

Vorraussetzungen:
- ein paar Linux Kenntnisse (ich versuche es aber so einfach wie möglich zu beschreiben)
- ein verbundener Repetier Server (z.B.: installiert auf einem Raspberry, muss aber nicht unbedingt sein, aber mit dem raspi hab ichs am laufen)
- websocket-client installiert (open-source, ich verwende den websocket_client-0.37.0)
- python 2.7 (sollte mit 3.0 auch gehen, getestet habe ichs aber mit 2.7, da mein Touch-Interface schon ziemlich alt ist...)

Wenn diese Vorraussetzungen gegeben sind, kanns los gehen:

1.) Verzeichnis ansurfen, wo das Script liegen soll (da kann man natürlich auch einen anderen Ordner wählen):
cd /home/pi/
2.) python-script-file erstellen:
vi websocket.py
3.) folgenden Code einfügen (zum einfügen zuerst die Taste "i" drücken), und dann, sofern man in einer putty-session arbeitet, den kopierten Code mittels rechtsklick einfügen. Achtung: am besten vor dem kopieren die Felder unter Config anpassen

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
###################################################################################
# Version 1.0
# Versionshinweise siehe version.txt
###################################################################################

import sys
from websocket import create_connection

funktion                        = sys.argv[1]
mode1                           = sys.argv[2]

######################################################################################################################
################################################## KONFIG ############################################################
######################################################################################################################

# file_drucker_befehl_id: dient nur dazu, dass 2 aufeinanderfolgenden Befehle nicht mit derselben ID geschickt werden
# muss nicht veraendert werden!!!
file_drucker_befehl_id  = "./drucker_befehl_id"
# Hostname/IP vom Reptier-Server - Achtung, beim verwenden von Hostname muss dieser als Mapping im File /etc/hosts hinterlegt sein
hostname_rep_server = "192.168.1.XXX"
# logischer Druckername, der im Reptier-Server bei der Initial-Konfig hinterlegt wurde
# das \" vor und nach dem Druckernamen muss da stehen, da es benoetigt wird - nur RF2000 gegen den richtigen Namen tauschen!
logischer_drucker_name = "\"RF2000\""

######################################################################################################################
################################################## MAIN ##############################################################
######################################################################################################################


def start_up():
        # ID fuer Druckbefehle auf 900 setzen
        write_to_file(file_drucker_befehl_id,"900",'w')


def websocket(mode1):
        fin = open(file_drucker_befehl_id,"r")
        drucker_befehl_id = fin.readline().replace("\n","")
        fin.close()
        drucker_befehl_id = int(drucker_befehl_id)
        drucker_befehl_id = drucker_befehl_id + 1
        mode1 = "\"" + mode1 + "\""
        ws = create_connection("ws://" + hostname_rep_server + "/socket/")
        b = ws.send("""{"action":"send","data":{"cmd":""" + mode1 + """},"printer":"""" + logischer_drucker_name + """","callback_id":""" + str(drucker_befehl_id) + "}")
        result =  ws.recv()
        ws.close()
        write_to_file(file_drucker_befehl_id,str(drucker_befehl_id),'w')

def write_to_file(file,text,mode):
        f = open(file,mode)
        f.write(text)
        f.close()

if __name__ == "__main__":
        if funktion == "start_up":
          start_up()
        elif funktion == "websocket":
          websocket(mode1)
4.) ESC drücken zum verlassen des Insert Modus
5.) :wq eintippen, zum speichern und verlassen
6.) chmod +x websocket.py eintippen, sodass das Script ausführbar ist

Das wars schon, folgendes Hintergrundwissen zu der websocket Thematik:
wird ein Befehl an den Drucker geschickt, muss dieser Befehl immer eine ID enthalten. Wozu? websocket ist eine bidirektionale Schnittstelle. Wird ein Befehl gesendet, erwartet sich der Sender immer eine Antwort. Kommt keine Antwort vom Empfänger ("habs bekommen, und folgendes damit gemahct:...", schickt der Sender den Befehl nochmal. Damit alle Befehle abgearbeitet werden können, und auch eine Liste an Befehlen geschickt werden kann, muss jeder nachfolegnde Befehl eine höhrere ID als der zuletzt gesendete Befehl haben. So wird auch sichergestellt, dass alles in der korrekten Reihenfolge abgearbeitet wird.
Damit das alles funktioniert, sollte man (am besten immer bei Raspberry start, z.b.: mitteln cronjob on start - oder beim initialisieren der Touch-Oberfläche) die Initial-Funktion aufrufen:
python /home/pi/websocket.py start_up
Das sorgt dafür, dass die Druckerbefehls-ID bei 900 beginnt - bei jedem Aufruf der Funktion wird dieser Wert dann um 1 erhöht.

Ein Beispiel dazu (und damit auch gleich der Aufruf des Script):
Output Object:
python /home/pi/websocket.py websocket "M400"
python /home/pi/websocket.py websocket "M3079"
python /home/pi/websocket.py websocket "M400"

Das ist nur ein kleiner Teil meines Gesamtscripts, und dementsprechend nur aus dem langen Code rausgezogen, und mit globalen Variablen versehen.

Das websocket_client.tgz könnte ich bei Bedarf auch hier hochladen, ist aber auch auf github zu finden, und .tgz files zu verteilen ist nie sehr vertrauenswürdig :D

Bei Fragen stehe ich gerne zur Verfügung, falls Leute Interesse an solchen Funktionen haben, kann ich noch weitere Teile meines Overall Programms hier posten.

LG Thomas

Re: Anleitung: Drucker per websocket ansteuern

Verfasst: Sa 7. Jan 2017, 22:14
von Wessix
Bin kein Linux experte, aber nachdem ich mir gerade den Kopf verbogen habe mit Fehlermeldungen sei angemerkt, Es ist klüger das eigene Pythonscript NICHT wie eine moduldatei zu nennen........
Also die selbst erstellte Datei am besten websocketrfx000.py nennen!!

oh man 2 h für den a....

so nach 2 weiteren stunden ........ :mann:
in der Zeile

Code: Alles auswählen

 b = ws.send("""{"action":"send","data":{"cmd":""" + mode1 + """},"printer":"""" + logischer_drucker_name + """","callback_id":""" + str(drucker_befehl_id) + "}")
sind zumindest unter python3 zwei " zuviel

Sie muss so aussehen

Code: Alles auswählen

b = ws.send("""{"action":"send","data":{"cmd":""" + mode1 + """},"printer":""" + logischer_drucker_name + ""","callback_id":""" + str(drucker_befehl_id) + "}")

nun bekomme ich zumindest eine acces denied antwort vom Repetier server :dash:

Re: Anleitung: Drucker per websocket ansteuern

Verfasst: So 8. Jan 2017, 10:41
von Wessix
So ich bin nun einiges weiter und wenn ich meinen Repetier Server Benutzer mit PW lösche kann ich mich sogar anmelden. Leider ist das keine tolle option sodass ich froh wäre wenn mit jemand den korrekten Übergabe String für den Login helfen könnte.
Hier steht unter Login Beschrieben wies gehen sollte:
https://www.repetier-server.com/manuals ... index.html

alternativ wäre die Übergabe des Apikeys, aber auch da habe ich den passenden JSON String nicht gefunden.

so soll die PW berechnung wohl gehen:

Code: Alles auswählen

Authenticates a user. Password is MD5(sessionId + MD5(login + password)) so it never goes in clear text over the line. If authentication is required, you get a loginRequired event directly after connecting to the socket.

nun habe ich entsprechend der Formel schon in allen möglichen Versionen versucht den MD5 zu erstellen aber bekomme immer einen invalid user or pw.... :diabolisch:

Code: Alles auswählen

 c = ws.send("""{"action":"ping","data":{},"printer":"MyPrinter","callback_id":""" + str(drucker_befehl_id) + "}")
        result =  ws.recv()
        print(str(result))
        if "session" in (result):
            sessionidtemp = (result.split("\"session\":",1)[1])
            sessionid = sessionidtemp[:-1]
            print(sessionid)
        else:
            pass
        bn="meinbenutzer"
        pw="meinpwasswort"
        md5bnpwgesamt=(hashlib.md5((bn+pw).encode('utf-8')).hexdigest())
        md5combined=(hashlib.md5((sessionid+md5bnpwgesamt).encode('utf-8')).hexdigest())
        print(md5combined)
        md5final = '"'+md5combined+'"'
        print(md5final)
        a = ws.send('{"action": "login", "callback_id":' + str(drucker_befehl_id) + """, "data": {"login":"meinbenutzer", "password":""" + md5final +'}}')


            
            
            

oder kann es daran liegen wie ich die MD5 codes erstelle?
hab die se methode bei stackoverflow als empfeohlene Variante ausgemacht?




hier steht noch beschrieben dass man die Aufrufe richtg URL encoden muss, gilt aber wahrscheinlich nur für den Browserleistenaufruf???
https://forum.repetier.com/discussion/c ... ment_10322


Warum will ich das ganze hinbekommen? Mit dem Websocket zugriffe kann man vom Rasoberry pi z.b. M oder G Codes an den Drucker senden aufrgund vorangegeangener Berechnungen/Abfragen usw. die auf dem Raspberry stattfinden können. In meinem Fall will ich eine DIgit Warnung einbauen die eben rechtzeitig warnt bevor der Druckern in den Emergency stopp geht.