|
| 1 | +# SPDX-FileCopyrightText: 2021 Patrick Van Oosterwijck @ Silicognition LLC |
| 2 | +# |
| 3 | +# SPDX-License-Identifier: MIT |
| 4 | +# |
| 5 | +# This demo was tested with the PoE-FeatherWing, which contains a 24AA02E48 |
| 6 | +# chip to provide a globally unique MAC address, but can also work without |
| 7 | +# this chip for testing purposes by using a hard coded MAC. |
| 8 | +# |
| 9 | +# It also contains a `get_static_file` function that demonstrates how to |
| 10 | +# use a generator to serve large static files without using up too much |
| 11 | +# memory. To avoid having to put extra files in the repo, it just serves |
| 12 | +# `code.py` which isn't very large, but to properly test it, adjust the code |
| 13 | +# to serve an image of several 100 kB to see how it works. |
| 14 | +# |
| 15 | +# There's also an endpoint that demonstrates that `requests` can be used to |
| 16 | +# get data from another socket and serve it. |
| 17 | +# |
| 18 | + |
| 19 | +import board |
| 20 | +import busio |
| 21 | +import digitalio |
| 22 | +import neopixel |
| 23 | + |
| 24 | +import adafruit_requests as requests |
| 25 | +from adafruit_wsgi.wsgi_app import WSGIApp |
| 26 | +from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K |
| 27 | +import adafruit_wiznet5k.adafruit_wiznet5k_socket as socket |
| 28 | +import adafruit_wiznet5k.adafruit_wiznet5k_wsgiserver as server |
| 29 | + |
| 30 | + |
| 31 | +print("Wiznet5k Web Server Test") |
| 32 | + |
| 33 | + |
| 34 | +def get_mac(i2c_obj): |
| 35 | + "Read MAC from 24AA02E48 chip and return it" |
| 36 | + mac_addr = bytearray(6) |
| 37 | + while not i2c_obj.try_lock(): |
| 38 | + pass |
| 39 | + i2c_obj.writeto(0x50, bytearray((0xFA,))) |
| 40 | + i2c_obj.readfrom_into(0x50, mac_addr, start=0, end=6) |
| 41 | + i2c_obj.unlock() |
| 42 | + return mac_addr |
| 43 | + |
| 44 | + |
| 45 | +def get_static_file(filename): |
| 46 | + "Static file generator" |
| 47 | + with open(filename, "rb") as f: |
| 48 | + b = None |
| 49 | + while b is None or len(b) == 2048: |
| 50 | + b = f.read(2048) |
| 51 | + yield b |
| 52 | + |
| 53 | + |
| 54 | +# Status LED |
| 55 | +led = neopixel.NeoPixel(board.NEOPIXEL, 1) |
| 56 | +led.brightness = 0.3 |
| 57 | +led[0] = (255, 0, 0) |
| 58 | + |
| 59 | +# Chip Select for PoE-FeatherWing and Adafruit Ethernet FeatherWing |
| 60 | +cs = digitalio.DigitalInOut(board.D10) |
| 61 | +# Chip Select for Particle Ethernet FeatherWing |
| 62 | +# cs = digitalio.DigitalInOut(board.D5) |
| 63 | + |
| 64 | +# Initialize SPI bus |
| 65 | +spi_bus = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) |
| 66 | + |
| 67 | +try: |
| 68 | + # Initialize the I2C bus to read the MAC |
| 69 | + i2c = busio.I2C(board.SCL, board.SDA) |
| 70 | + # Read the MAC from the 24AA02E48 chip |
| 71 | + mac = get_mac(i2c) |
| 72 | +except (RuntimeError, OSError): |
| 73 | + # Hard coded MAC if there is no 24AA02E48 |
| 74 | + mac = b"\xFE\xED\xDE\xAD\xBE\xEF" |
| 75 | + |
| 76 | +# Initialize Ethernet interface with DHCP |
| 77 | +eth = WIZNET5K(spi_bus, cs, mac=mac) |
| 78 | + |
| 79 | +# Initialize a requests object with a socket and ethernet interface |
| 80 | +requests.set_socket(socket, eth) |
| 81 | + |
| 82 | + |
| 83 | +# Here we create our application, registering the |
| 84 | +# following functions to be called on specific HTTP GET requests routes |
| 85 | + |
| 86 | +web_app = WSGIApp() |
| 87 | + |
| 88 | + |
| 89 | +@web_app.route("/led/<r>/<g>/<b>") |
| 90 | +def led_on(request, r, g, b): # pylint: disable=unused-argument |
| 91 | + print("LED handler") |
| 92 | + led.fill((int(r), int(g), int(b))) |
| 93 | + return ("200 OK", [], ["LED set!"]) |
| 94 | + |
| 95 | + |
| 96 | +@web_app.route("/") |
| 97 | +def root(request): # pylint: disable=unused-argument |
| 98 | + print("Root WSGI handler") |
| 99 | + return ("200 OK", [], ["Root document"]) |
| 100 | + |
| 101 | + |
| 102 | +@web_app.route("/large") |
| 103 | +def large(request): # pylint: disable=unused-argument |
| 104 | + print("Large pattern handler") |
| 105 | + return ("200 OK", [], ["*-.-" * 2000]) |
| 106 | + |
| 107 | + |
| 108 | +@web_app.route("/code") |
| 109 | +def code(request): # pylint: disable=unused-argument |
| 110 | + print("Static file code.py handler") |
| 111 | + return ("200 OK", [], get_static_file("code.py")) |
| 112 | + |
| 113 | + |
| 114 | +@web_app.route("/btc") |
| 115 | +def btc(request): # pylint: disable=unused-argument |
| 116 | + print("BTC handler") |
| 117 | + r = requests.get("http://api.coindesk.com/v1/bpi/currentprice/USD.json") |
| 118 | + result = r.text |
| 119 | + r.close() |
| 120 | + return ("200 OK", [], [result]) |
| 121 | + |
| 122 | + |
| 123 | +# Here we setup our server, passing in our web_app as the application |
| 124 | +server.set_interface(eth) |
| 125 | +wsgiServer = server.WSGIServer(80, application=web_app) |
| 126 | + |
| 127 | +print("Open this IP in your browser: ", eth.pretty_ip(eth.ip_address)) |
| 128 | + |
| 129 | +# Start the server |
| 130 | +wsgiServer.start() |
| 131 | +led[0] = (0, 0, 255) |
| 132 | + |
| 133 | +while True: |
| 134 | + # Our main loop where we have the server poll for incoming requests |
| 135 | + wsgiServer.update_poll() |
| 136 | + # Maintain DHCP lease |
| 137 | + eth.maintain_dhcp_lease() |
| 138 | + # Could do any other background tasks here, like reading sensors |
0 commit comments