Code Monkey home page Code Monkey logo

esp8266-captive-portal's Introduction

Blog post series

The code in this repo is the results of a blog series I wrote about building a captive web portal for a Wemos D1 Mini using MicroPython. You can find the articles here:

Starting the captive portal

Copy the .py and .html files to your ESP8266 board. If you already have a main.py file, then just copy the contents of the main.py file from this repo. There's only a couple of lines there.

Instantiating a CaptivePortal and calling its start() method will turn on your MCU's WiFi access point, and you can then connect to it and input your home WiFi credentials. Once you do, the MCU will turn off its AP, and connect to your home WiFi instead.

Purpose

This is not really a standalone project, but rather a bit of useful functionality that I drop into other projects I make so that if I send one to someone else, I don't need to hardcode their home WiFi credentials to get the thing to work. Instead, they can easily enter their own WiFi SSID and password to allow the device to connect and start doing whatever it's supposed to be doing.

esp8266-captive-portal's People

Contributors

acidkewpie avatar anson-vandoren avatar grey27 avatar jasonbrackman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

esp8266-captive-portal's Issues

The endless loop should be terminated

The captive_portal() func has a loop, there is no end when the configuration is complete,I think we should break after DNS is turned off,Otherwise, methods after portal.start() cannot be run.

if self.check_valid_wifi():
    print("Connected to WiFi!")
    self.http_server.set_ip(self.local_ip, self.ssid)
    self.dns_server.stop(self.poller)
    break

This is a great project, please forgive my grammar, because English is not my native language

credentials re-written even when valid

Each restart of the esp8266 that has valid credentials currently rewrites the file.

While this should be fine, it is possible to write a partial file if the write is interrupted.

I wasn't 100% sure if there was a better place, but imagine that the write_creds() in captive_portal.py could do the following?

    def write_creds(self, ssid, password):
        try:
            os.stat(self.CRED_FILE)
        except OSError:
            open(self.CRED_FILE, "wb").write(b",".join([ssid, password]))
            print("Wrote credentials to {:s}".format(self.CRED_FILE))

and the try_connect_from_file() func would need to either remove the else clause if the ssid/password is not present or an `os.remove(self.CRED_FILE) would need to be added

Error running on ESP32 as is. Any idea what should be changed?

Starting captive portal
Waiting for access point to turn on
AP mode configured: ('192.168.4.1', '255.255.255.0', '192.168.4.1', '192.168.4.1')
HTTP Server listening on ('0.0.0.0', 80)
Configured HTTP server
DNS Server listening on ('0.0.0.0', 53)
Configured DNS server
Sending www.gstatic.com. -> 192.168.4.1
Sending www.google.com. -> 192.168.4.1
Sending www.gstatic.com. -> 192.168.4.1

  • Accepting new HTTP connection
    Sending www.google.com. -> 192.168.4.1
    Sending www.gstatic.com. -> 192.168.4.1
  • Reading incoming HTTP data
  • Accepting new HTTP connection
    Sending www.youtube.com. -> 192.168.4.1
  • Sending outgoing HTTP data
    Sending ssl.gstatic.com. -> 192.168.4.1
  • Reading incoming HTTP data
  • Accepting new HTTP connection
    Sending www.gstatic.com. -> 192.168.4.1
  • Sending outgoing HTTP data
  • Accepting new HTTP connection
    Sending www.google.com. -> 192.168.4.1
  • Reading incoming HTTP data
    Sending spclient.wg.spotify.com. -> 192.168.4.1
  • Sending outgoing HTTP data
  • Reading incoming HTTP data
  • Accepting new HTTP connection
    Sending mtalk.google.com. -> 192.168.4.1
  • Sending outgoing HTTP data
    Sending dealer.spotify.com. -> 192.168.4.1
  • Reading incoming HTTP data
    Sending dealer.spotify.com. -> 192.168.4.1
  • Sending outgoing HTTP data
    Sending 0.client-channel.google.com. -> 192.168.4.1
  • Sending outgoing HTTP data
    Sending signaler-pa.clients6.google.com. -> 192.168.4.1
  • Sending outgoing HTTP data
    Sending clients4.google.com. -> 192.168.4.1
  • Sending outgoing HTTP data
    Sending oauthaccountmanager.googleapis.com. -> 192.168.4.1
    Sending favrohdoy. -> 192.168.4.1
  • Accepting new HTTP connection
    Sending yuxjawivfx. -> 192.168.4.1
  • Accepting new HTTP connection
    Sending yqncsolbleyg. -> 192.168.4.1
  • Reading incoming HTTP data
  • Accepting new HTTP connection
  • Sending outgoing HTTP data
  • Accepting new HTTP connection
    Sending calendar.google.com. -> 192.168.4.1
  • Reading incoming HTTP data
  • Reading incoming HTTP data
  • Reading incoming HTTP data
  • Sending outgoing HTTP data
  • Sending outgoing HTTP data
  • Sending outgoing HTTP data
  • Sending outgoing HTTP data
  • Accepting new HTTP connection
  • Sending outgoing HTTP data
    Traceback (most recent call last):
    File "main.py", line 5, in
    File "captive_portal.py", line 168, in start
    File "captive_portal.py", line 125, in captive_portal
    File "captive_portal.py", line 147, in handle_http
    File "captive_http.py", line 223, in write_to
    OSError: [Errno 104] ECONNRESET

How is connection.html supposed to be served?

First of all, I really like this. It works nicely with my android phone to get the target device into the desired WiFi. Nice!

But I don't understand how the connection.html is to be served. Once the wifi setup is done the main loop isn't run anymore, no polling takes place and thus the http server will not serve anything afterwards. The readme even states that the AP is stopped once station mode is connected.

But imho the esp supports to run in ap and sta mode at the same time. So it should be possible to keep the AP running and allow for a nice redirect to a page served on sta side.

What am I missing?

has_creds() uses a cached input and never resets (bad input will loop)

The captive_portal() func has a loop that involves a call to check_valid_wifi() that calls a has_creds() function. The has_creds() will never return None once an ssid/password is entered as it is never cleared.

def has_creds(self):
    self.ssid, self.password = self.http_server.saved_credentials <-- HERE
    return None not in [self.ssid, self.password]

I feel like the connect_to_wifi() func might be the best place to negate the cached values as you are already setting the self.ssid/self.password to None anyway?

...
# forget the credentials since they didn't work, and turn off station mode
self.http_server.saved_credentials = [None, None]
self.ssid = self.password = None
self.sta_if.active(False)
...

This project works on the ESP32 too?

Hello, I would like to have a captive portal on my ESP32. My intention is in really that when mobile user acess de ESP32 Access Point without password, can open automatically the default browser on the SO (Android/IOS) with the IP of ESP32 device, without user needs to type the ESP32 IP on the browser.

I think that the captive portal will works for this purpose, right?

Ps: Mobile user do not need access the internet via ESP32, just access automatically the ESP32 HTTP page on it.

Thank you!

Lost wifi.creds text after multiple reboots

code:

from captive_portal import CaptivePortal

portal = CaptivePortal()
contents = open("./wifi.creds", "rb").read().split(b",")
print()
print('VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV')
print(contents)
portal.start()
print(contents)
print('------------------------------------------')

logs:

# First restart
$l`��rےo��l$ �

VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
[b'MERCURY_6510', b'104104104104']
Trying to load WiFi credentials from ./wifi.creds
Trying to connect to SSID 'MERCURY_6510' with password 104104104104
#6 ets_task(4020f4d8, 28, 3fff9348, 10)
Connection in progress
Connection in progress
Connected to MERCURY_6510
Wrote credentials to ./wifi.creds
[b'MERCURY_6510', b'104104104104']
------------------------------------------
MicroPython v1.12 on 2019-12-20; ESP module with ESP8266
Type "help()" for more information.
>>> 

# Second restart
�$l`�
�l$䌎2#
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
[b'']
Trying to load WiFi credentials from ./wifi.creds
Invalid credentials file: [b'']
Starting captive portal
Waiting for access point to turn on
#6 ets_task(4020f510, 29, 3fff8bc8, 10)
AP mode configured: ('192.168.4.1', '255.255.255.0', '192.168.4.1', '192.168.4.1')
HTTP Server listening on ('0.0.0.0', 80)
Configured HTTP server

I guess the text was not closed, so it was not saved
this problem can be solved by using with

def write_creds(self, ssid, password):
        with open(self.CRED_FILE, "wb") as fp:
                fp.write(b",".join([ssid, password]))
        #open(self.CRED_FILE, "wb").write(b",".join([ssid, password]))
        print("Wrote credentials to {:s}".format(self.CRED_FILE))

Well written blog on Captive Portal

I have written an uasyncio task based on your code along with nano webserver. I am on Ubuntu and my Captive Portal app launches when I connect to ESP Access point. the Index page loads on the captive portal app - but the style sheet doesn't load.

However when I use a browser, I get both the page and style sheet (I have cleared cache to test it).

Do you have any thoughts on this.

Do you have any suggestion for reading material to learn python asyncio/threads?

No method to handle url escape characters

Special characters are represented as url escape from the html form. For example, ! is changed %21. This change prevents connecting to my wifi. I tried to correct this with urllib.parse.unquote, but that method used a particular string split that is not implemented in micropython, returning a NotImplemented error.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.