Julian
Julian

Reputation: 11

TypeError: function takes 4 positional arguments but 5 were given in micropython script

so i have been building a project for connecting my esp8266 to wifi using micropython but whenever i run the script it gives this error

>>> import main
trying to load wifi credentials from ./wifi.creds
./wifi.creds does not exist 
starting captive portal
Waiting for access Point To turn on
#12 ets_task(4020f510, 29, 3fff9428, 10)
AP mode Configured: ('210.210.210.1', '255.255.255.0', '210.210.210.1', '210.210.210.1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "main.py", line 5, in <module>
  File "captive_portal.py", line 37, in start
  File "captive_portal.py", line 93, in captive_portal
  File "captive_dns.py", line 55, in __init__
TypeError: function takes 4 positional arguments but 5 were given

so the script is supposed to print dns request made from my phone once it has connected to the AP created by the esp8266 board. but it keeps printing the error message . here is my are my scripts for the project

from captive_portal import CaptivePortal

portal = CaptivePortal()

portal.start()
captive_portal.py
import network
import uerrno
import uos as os
import utime as time
import gc 
import uselect as select
from captive_dns import DNSServer



class CaptivePortal():
    AP_IP = "210.210.210.1"
    CRED_FILE = "./wifi.creds"
    MAX_CONN_ATTEMPTS = 10
    

    def __init__(self, essid = None):
        self.local_ip = self.AP_IP
        self.sta_if = network.WLAN(network.STA_IF)
        self.ap_if = network.WLAN(network.AP_IF)

        if essid is None:
            essid = "FAKEAP"
        self.essid = essid  

        self.dns_server = None
        self.poller = select.poll()  

        self.ssid = None
        self.password = None


    def start(self):
        #turn off station interface to force reconnect
        self.sta_if.active(False)
        if not self.try_connect_from_file():
            self.captive_portal()


    def connect_to_wifi(self):
        print(
            "Trying to connect using SSID '{:s}' with password {:s}".format(
                self.ssid, self.password
            )
        )   
        #initiate the connection 
        self.sta_if.active(True)
        self.sta_if.connect(self.ssid, self.password)

        attempts = 0 
        while attempts < self.MAX_CONN_ATTEMPTS:
            if not self.sta_if.isconnected():
                print("connection in progress")
                time.sleep(2)
                attempts += 1
            else:
                print("connected to {:s}".format(self.ssid))
                self.local_ip = self.sta_if.ifconfig()[0] 
                self.write_creds(self.ssid, self.password)
                return True   
                

        print("Failed to connect to {:s} with {:s}. WLAN status={:d}".format(
            self.ssid, self.password, self.sta_if.status()
        ))        
        #forget the credentials since they didnt work, and turn off station mode 
        self.ssid = self.password = None
        self.sta_if.active(False)
        return False

    def write_creds(self, ssid, password):
        open(self.CRED_FILE, 'wb').write(b','.join([ssid, password]))
        print("wrote credentials to {:s}".format(self.CRED_FILE))

    def start_access_point(self):
        #sometimes need to turn off AP before it comes up properly
        self.ap_if.active(False)
        while not self.ap_if.active():
            print("Waiting for access Point To turn on")
            self.ap_if.active(True)
            time.sleep(4)
        #setup a DNS server to redirect all connected clients Traffic
        self.ap_if.ifconfig((self.local_ip, "255.255.255.0", self.local_ip, self.local_ip))  
        self.ap_if.config(essid=self.essid, authmode=network.AUTH_OPEN)
        print("AP mode Configured:", self.ap_if.ifconfig())


    def captive_portal(self):
        print("starting captive portal") 
        self.start_access_point()

        if self.dns_server is None:
            self.dns_server = DNSServer(self.poller, self.local_ip)
            print("DNS Server has been Configured")

        try:
            while True:
                gc.collect()
                #check for socket events and handle them
                for response in self.poller.ipoll(1000):
                    sock, events, *others = response
                    self.handle_dns(sock, events, others)
        except KeyboardInterrupt:
            print("Captive portal stopped")
            self.cleanup()

    def handle_dns(self, sock, event, others):
        if sock is self.dns_server.sock:
            #ignore UDP sockets  hangup
            if events == select.POLLHUP:
                return True
                self.dns_server.handle(sock, event, others)
                return True
            return False

    def cleanup(self):
        print("cleaning up")
        if self.dns_server:
            self.dns_server.stop(self.poller)
        gc.collect()                


    def try_connect_from_file(self):
        print("trying to load wifi credentials from {:s}".format(self.CRED_FILE))
        try:
            os.stat(self.CRED_FILE)
        except OSError as e:
            if e.args[0] == uerrno.ENOENT:
                print("{:s} does not exist ".format(self.CRED_FILE))
                return False

        contents = open(self.CRED_FILE, 'rb').read().split(b',')
        if len(contents) == 2:
            self.ssid, self.password = contents
        else:
            print("Invalid Credentials Files:", contents)
            return False

        if not self.connect_to_wifi():
            print("conect with wifi credentials failed, Starting Captive portal")
            os.remove(self.CRED_FILE)
            return False

        return True            



captive_dns.py
import usocket as socket
import gc

from server import Server

class DNSServer(Server):
    def __init__(self, poller, ip_addr):
        super().__init__(poller, 53, socket.SOCK_DGRAM, "DNS Server")
        self.ip_addr = ip_addr

    def handle(self, sock, event, others):
        # server doesn't spawn other sockets, so only respond to its own socket
        if sock is not self.sock:
            return

        # check the DNS question, and respond with an answer
        try:
            data, sender = sock.recvfrom(1024)
            request = DNSQuery(data)

            print("Sending {:s} -> {:s}".format(request.domain, self.ip_addr))
            sock.sendto(request.answer(self.ip_addr), sender)

            # help MicroPython with memory management
            del request
            gc.collect()
        except Exception as e:
            print("DNS server exception:", e)

server.py
import usocket as socket
import uselect as select

class Server:
    def __init__(self, poller, sock_type, name):
        self.name = name
        # create socket with correct type : stream (TCP) or datagrams (UDP)
        self.sock = socket.socket(socket.AF_INET, sock_type)


        #register to get event update for this socket
        self.poller = poller
        self.poller.register(self.sock, select.POLLIN)

        addr = socket.getaddrinfo("0.0.0.0", port) [0] [-1]
        #allow new request while sending last response
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(addr)


        print(self.name , "listening on", addr)


    def stop(self, poller):
        poller.unregister(self.sock)
        self.sock.close()
        print(self.name, "stopped")    

Upvotes: 0

Views: 711

Answers (1)

Guru Stron
Guru Stron

Reputation: 143098

It seems that your Server is missing a port parameter in the third position of __init__ (which is later used in addr = socket.getaddrinfo("0.0.0.0", port) [0] [-1]):

class Server:
    def __init__(self, poller, port, sock_type, name):

Upvotes: 1

Related Questions