Accept user input with adafruit_httpserver

CircuitPython on hardware including Adafruit's boards, and CircuitPython libraries using Blinka on host computers.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
greenleaf
 
Posts: 21
Joined: Sat Jun 25, 2011 10:18 pm

Accept user input with adafruit_httpserver

Post by greenleaf »

Anyone have an example of accepting input from a user via the web browser?

For example, exposing a text box to the user and then showing what was typed on a small display.

User avatar
greenleaf
 
Posts: 21
Joined: Sat Jun 25, 2011 10:18 pm

Re: Accept user input with adafruit_httpserver

Post by greenleaf »

I can see from the NeoPixel example that you can change request parameters in a URL:

https://docs.circuitpython.org/projects ... ixel-color

Wondering if there's a way to enable direct user input via a form...or code to take what's in the form and submit it as a URL parameter?

User avatar
neradoc
 
Posts: 542
Joined: Wed Apr 27, 2016 2:38 pm

Re: Accept user input with adafruit_httpserver

Post by neradoc »

Hi, here is an example with a text field.

https://gist.github.com/Neradoc/fd29d5a ... 9345027930

If the mdns works on your network it should show up as http://text-setter.local:8080/
When you press enter it sends the text and prints it to the REPL. The code to show the text on a display will be easily added from the examples of whatever display you are using.

Files should be placed like that (the blinka favicon is optional)
screen1.png
screen1.png (30.16 KiB) Viewed 80 times
Since it uses os.getenv/settings.toml, it requires Circuitpython 8.0.0 beta 6 or later, but you can change the connection code if you need to.

Here is the code (the same as the gist above).
code.py

Code: Select all

# SPDX-FileCopyrightText: 2023 Neradoc
# SPDX-License-Identifier: MIT
"""Press a button on the web page to cycle the colors"""
import board
import mdns
import microcontroller
import socketpool
import time
import wifi
import os

from adafruit_httpserver.server import HTTPServer
from adafruit_httpserver.response import HTTPResponse
from adafruit_httpserver.mime_type import MIMEType

MDNS_NAME = "text-setter"
PORT = 8080
ROOT = "/www"

############################################################################
# MDNS
############################################################################

mdnserv =  mdns.Server(wifi.radio)
mdnserv.hostname = MDNS_NAME
mdnserv.advertise_service(service_type="_http", protocol="_tcp", port=PORT)

############################################################################
# wifi
############################################################################

wifi.radio.connect(
    os.getenv("CIRCUITPY_WIFI_SSID"),
    os.getenv("CIRCUITPY_WIFI_PASSWORD")
)
print(f"Listening on http://{wifi.radio.ipv4_address}:{PORT}")

pool = socketpool.SocketPool(wifi.radio)
server = HTTPServer(pool)

############################################################################
# server routes and app logic
############################################################################

@server.route("/")
def base(request):
    """Default reponse is /index.html"""
    print("/ -> index.html")
    with HTTPResponse(request, content_type=MIMEType.TYPE_HTML) as response:
        response.send_file(f"{ROOT}/index.html")

@server.route("/text")
def base(request):
    # receive a text
    the_text = request.query_params.get("the_text", "")
    print(f"Received: {the_text}")
    with HTTPResponse(request, content_type=MIMEType.TYPE_HTML) as response:
        response.send("ok")

############################################################################
# start and loop
############################################################################

IP_ADDRESS = wifi.radio.ipv4_address or wifi.radio.ipv4_address_ap
server.start(host=str(IP_ADDRESS), port=PORT, root_path=ROOT)

while True:
    server.poll()
    time.sleep(0.01)
index.html

Code: Select all

<!doctype html>
<html lang="en">
<!-- 
SPDX-FileCopyrightText: Copyright 2023 Neradoc, https://neradoc.me
SPDX-License-Identifier: MIT
 -->
<head>
	<meta charset="utf-8"/>
	<link rel="icon" href="/blinka.png"/>
	<title>Button</title>
	<script>
	function send_text(field, event) {
		console.log(field.value)
		console.log(event)
		if(event.keyCode == 13) {
			fetch(`/text?the_text=${field.value}`)
		}
	}
	</script>
</head>
<body>
	<div>Press enter to send: <input type="text" onkeyup="send_text(this, event)"/></div>
</body>
</html>

User avatar
greenleaf
 
Posts: 21
Joined: Sat Jun 25, 2011 10:18 pm

Re: Accept user input with adafruit_httpserver

Post by greenleaf »

Thanks, this is rad! Much cleaner than what I came up with on my own. This outputs the message to a little OLED display on my desk:

Code: Select all

from config_secrets import secrets

import json
import microcontroller
import socketpool
import wifi
import board
import busio as io
import adafruit_displayio_ssd1306
import time
import terminalio
import displayio
from adafruit_display_text import label, wrap_text_to_lines

from adafruit_httpserver.mime_type import MIMEType
from adafruit_httpserver.request import HTTPRequest
from adafruit_httpserver.response import HTTPResponse
from adafruit_httpserver.server import HTTPServer

ssid, password = secrets['WIFI_SSID'], secrets['WIFI_PASSWORD']
print("Connecting to", ssid)
wifi.radio.connect(ssid, password)

pool = socketpool.SocketPool(wifi.radio)
server = HTTPServer(pool)

@server.route("/")
def base(request: HTTPRequest):
    """
    Serve the default index.html file.
    """
    with HTTPResponse(request, content_type=MIMEType.TYPE_HTML) as response:
        response.send_file("index.html")
        

displayio.release_displays()
i2c = io.I2C(board.SCL, board.SDA)
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=64)

# Make the display context
splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(128, 64, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF  # White

text_area = label.Label(terminalio.FONT, text="Ready to receive.", color=0xFFFF00, x=0, y=10)
splash.append(text_area)

@server.route("/index.html")
def send_message(request: HTTPRequest):
    message = request.query_params.get("message")
    message = "\n".join(wrap_text_to_lines(message, 20))
    text_area.text = message

    with HTTPResponse(request, content_type=MIMEType.TYPE_HTML) as response:
        response.send('''
            <html>
              <head><title>Meow!</title></head>
              <body>
              
              <style>
              body {
                background-image: url('ninjacat.jpg');
              }
              </style>
              
              <div style="width:800px;margin: 0 auto">
              <!-- BEGIN -->
              <center>
                <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
                <form method="get" action="/index.html">
                <input type="text" id="message" name="message"><br>
                <input type="submit" value="Send a Message"><br>
                </form>
                <h2 style="color:green;">Message Sent!</h2>
                </center>
              <!-- END -->
              </div>
              </body>
            </html>
        ''')

print(f"Listening on http://{wifi.radio.ipv4_address}:80")
server.serve_forever(str(wifi.radio.ipv4_address))

while True:
    pass

User avatar
neradoc
 
Posts: 542
Joined: Wed Apr 27, 2016 2:38 pm

Re: Accept user input with adafruit_httpserver

Post by neradoc »

Hey I realized that with my method the message is transmitted url-encoded, which would need to be decoded (%20 and all that). So instead I rewrote it to use POST with a json-encoded body, and while I was there I integrated the display text (also making it work on my FunHouse for tests) and I added a loading animation and confirmation ☑️ or error ❌️ icon.
I updated the gist above with it.

User avatar
greenleaf
 
Posts: 21
Joined: Sat Jun 25, 2011 10:18 pm

Re: Accept user input with adafruit_httpserver

Post by greenleaf »

Nice, thanks for the update. I'd been using str.replace() to strip out those URL encoded characters. The JSON solution is better!

Locked
Please be positive and constructive with your questions and comments.

Return to “Adafruit CircuitPython”