Webserver integrieren

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
unique24
User
Beiträge: 65
Registriert: Donnerstag 5. Juli 2018, 14:51

Hallo,

ich schreibe grad an einer Hühnerstall Software und möchte einen Webserver für get und post einbauen. Bekomme es aber nicht in meinem Programm zum laufen.

Ich möchte mit meinem Programm Daten per http get/post austauschen.

Aber ich erhalte den Fehler:
TypeError: __init__() takes 1 positional argument but 4 were given

Code: Alles auswählen

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

from http.server import BaseHTTPRequestHandler, HTTPServer

class Coop(BaseHTTPRequestHandler):
    HOST_NAME = '192.168.0.63'
    PORT_NUMBER = 9000

    def __init__(self):
        # init Webserver        
        server_class = HTTPServer
        httpd = server_class((Coop.HOST_NAME, Coop.PORT_NUMBER), Coop)
        print(time.asctime(), 'Server Starts - %s:%s' % (Coop.HOST_NAME, Coop.PORT_NUMBER))
        httpd.serve_forever()
        
   def do_HEAD(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

    def do_GET(self):
        paths = {
            '/foo': {'status': 200},
            '/bar': {'status': 302},
            '/baz': {'status': 404},
            '/qux': {'status': 500}
        }

        if self.path in paths:
            self.respond(paths[self.path])
        else:
            self.respond({'status': 500})

    def handle_http(self, status_code, path):
        self.send_response(status_code)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        content = '''
        <html><head><title>Title goes here.</title></head>
        <body><p>This is a test.</p>
        <p>You accessed path: {}</p>
        </body></html>
        '''.format(path)
        return bytes(content, 'UTF-8')

    def respond(self, opts):
        response = self.handle_http(opts['status'], self.path)
        self.wfile.write(response)
        
        
if __name__ == "__main__":   
    coop = Coop()
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Nimm doch einen fertigen Webserver, wie z.B. CherryPy, und integriere dort Deine Applikation.
unique24
User
Beiträge: 65
Registriert: Donnerstag 5. Juli 2018, 14:51

Danke,

ich denk aber das ich es hinbekommen habe:

Code: Alles auswählen

class ReportHandler(BaseHTTPRequestHandler):
    def do_HEAD(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

    def do_GET(self):
        paths = {
            '/foo': {'status': 200},
            '/bar': {'status': 302},
            '/baz': {'status': 404},
            '/qux': {'status': 500}
        }

        if self.path in paths:
            self.respond(paths[self.path])
        else:
            self.respond({'status': 500})

    def handle_http(self, status_code, path):
        self.send_response(status_code)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        content = Coop.createJson().format(path)
        return bytes(content, 'UTF-8')

    def respond(self, opts):
        response = self.handle_http(opts['status'], self.path)
        self.wfile.write(response)
        
        
Nun müsste ich aber von der Klasse "ReportHandler" Daten von der Klasse Coop holen. Dort habe ich eine Funktion:

Code: Alles auswählen

def createJson(self):
        data = {}
        data['door_state'] = self.door_status
        data['indoor_temp'] = self.indoor_temp
        data['indoor_humidity'] = self.indoor_humidity
        data['indoor_illumination'] = self.indoor_illumination
        data['indoor_light_1'] = self.indoor_light_1
        data['indoor_light_2'] = self.indoor_light_2
        data['indoor_light_3'] = self.indoor_light_3
        data['indoor_light_4'] = self.indoor_light_4
        data['indoor_light_5'] = self.indoor_light_5
        data['indoor_light_6'] = self.indoor_light_6
        data['indoor_water_temp'] = self.temp_water
        data['food_illumination'] = self.food_illumination
        
        data['outdoor_temp'] = self.outdoor_temp
        data['outdoor_humidity'] = self.outdoor_humidity
        data['outdoor_illumination'] = self.outdoor_illumination
        
        data['indoor_dawn_treshold'] = self.indoor_dawn_treshold
        data['indoor_dawn_hysteresis'] = self.indoor_dawn_hysteresis
        
        data['indoor_food_treshold'] = self.indoor_food_treshold
        data['indoor_food_hysteresis'] = self.indoor_food_hysteresis
        
        
        data['indoor_light_hours'] = self.indoor_light_hours
        data['indoor_dimming_time'] = self.indoor_dimming_time
        
        json_data = json.dumps(data)
        
        return json_data   
Wie kann ich das JSON von der anderen Klasse abrufen?
content = Coop.createJson().format(path)

Das gibt den Fehler aus:
TypeError: createJson() missing 1 required positional argument: 'self'
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

es gilt immer noch, dass man `http.server` eigentlich nicht benutzt, sondern ein Framework benutzt, je nach dem, was Du machen möchtest, bottle, flask, django, etc.
Das Klassendesign ist, wie ich im anderen Thread schon geschrieben habe, nicht sinnvoll.
`format` auf einen JSON-codierten String aufzurufen ist ein Fehler. Wenn Du Parameter hast, dann fügst Du die vorher in das Wörterbuch ein.
unique24
User
Beiträge: 65
Registriert: Donnerstag 5. Juli 2018, 14:51

Hallo,

ok, dann versuch ich cherrypy!

Code: Alles auswählen

import cherrypy

class Coop(object):
    @cherrypy.expose
    def index(self):
        return "Hello world!"

if __name__ == "__main__":   
    cherrypy.quickstart(Coop())
Sollte ich dann über "http://ip:8080/index" den Text "Hello world" zurück bekommen?

Danke!
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ohne index. Nur slash. Und dann geht es auch.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Probiere es doch aus. CherryPy habe ich empfohlen, da ich den Eindruck habe, dass Du nur wenige Handler benötigst, und CherryPy bereits einen brauchbaren Webserver mitbringt. Für solche Anwendungen ist CherryPy ganz prima. Ansonsten gibt es noch eine Menge weitere Frameworks, die ausgereift und brauchbar sind.
unique24
User
Beiträge: 65
Registriert: Donnerstag 5. Juli 2018, 14:51

Danke, es läuft nun.

Hatte wohl beim installieren etwas falsch ... schön auch wenn ich den python code ändere, das Programm nun gleich selber neustartet :-)
unique24
User
Beiträge: 65
Registriert: Donnerstag 5. Juli 2018, 14:51

Nun doch noch ein problem:
CORS

Ich rufe von einer Apache2 Webseite (vom selben Raspberry) eine Seite vom cherrypy auf:
http://192.168.0.63:8080/status

Von meinem PC aus klappt es mit cherrypy.

Aber vom Raspi selbst nicht.
Fehler im Firefox Inspector:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://192.168.0.63:8080/status. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

Ich habe https://pypi.org/project/cherrypy-cors/ installiert, aber nicht sicher ob ich es richtig eingepflegt habe:

Code: Alles auswählen

import cherrypy_cors
cherrypy_cors.install()

cherrypy.config.update({'server.socket_port': 8080, 'server.socket_host': '0.0.0.0', '/static': {'tools.staticdir.on': True, 'cors.expose.on': True}})
Oder liegt es an Apache2? Dort habe ich auch alles eingetragen was CORS betrifft.

Denk aber das es am cherrypy liegt?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das denke ich nicht. Denn das Request soll ja auf den cherrypy-Server gehen, und wird schon vorher blockiert.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Für was brauchst Du denn den Apache?
Und wie rufst Du denn von da aus den cherrypy auf?
Antworten