Instantly share code, notes, and snippets.
Last active
June 26, 2023 22:26
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save thurask/ecd9e4390f4c5e0948fa38ea80ddf6a2 to your computer and use it in GitHub Desktop.
Waveshare Pico Relay board web server for Pico W MicroPython
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import machine | |
import neopixel | |
import network | |
import os | |
import socket | |
import time | |
# WaveShare Pico Relay B board | |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
# Channel 1 = GPIO 21 | |
# Channel 2 = GPIO 20 | |
# Channel 3 = GPIO 19 | |
# Channel 4 = GPIO 18 | |
# Channel 5 = GPIO 17 | |
# Channel 6 = GPIO 16 | |
# Channel 7 = GPIO 15 | |
# Channel 8 = GPIO 14 | |
# RGB = GPIO 13 | |
# Buzzer = GPIO 6 | |
WLAN_SSID = "YOUR SSID" | |
WLAN_PASS = "YOUR PASSWORD" | |
class Buzzer(object): | |
def __init__(self, freq): | |
self.pin = 6 # WaveShare board | |
self.freq = freq | |
self.pwm = machine.PWM(machine.Pin(self.pin)) | |
self.pwm.freq(self.freq) | |
def beep(self, duration=0.5): | |
self.pwm.duty_u16(1000) | |
time.sleep(duration) | |
self.pwm.duty_u16(0) | |
def write_default_json(): | |
#Populate default channel values | |
stock_gpios = {f"channel_{chan+1}" : {"pin": pin, "active": False} for chan, pin in enumerate(range(21, 13, -1))} # 8 channels | |
with open("channels.json", "wb") as afile: | |
json.dump(stock_gpios, afile) | |
def write_default_secrets(): | |
#Populate default WLAN values | |
stock_secrets = {"ssid": WLAN_SSID, "password": WLAN_PASS} | |
with open("secrets.json", "wb") as afile: | |
json.dump(stock_secrets, afile) | |
def connect(): | |
#Connect to WLAN | |
wlan = network.WLAN(network.STA_IF) | |
wlan.config(hostname="picorelay") | |
wlan.active(True) | |
with open("secrets.json", "rb") as afile: # {ssid: YOURSSID, password: YOURPASSWORD} | |
jso = json.load(afile) | |
ssid = jso["ssid"] | |
password = jso["password"] | |
wlan.connect(ssid, password) | |
while wlan.isconnected() == False: | |
print('Waiting for connection...') | |
time.sleep(1) | |
ip = wlan.ifconfig()[0] | |
print(f'Connected on {ip}') | |
return ip | |
def open_socket(ip): | |
#Open a socket | |
address = (ip, 80) | |
connection = socket.socket() | |
connection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
connection.bind(address) | |
connection.listen(1) | |
return connection | |
def webpage(gpiodict): | |
#Template HTML | |
html= f"""<!DOCTYPE html> | |
<html> | |
<body> | |
<h3>PICO CONTROLS</h3> | |
<table> | |
<thead> | |
<tr> | |
<td>Channel</td> | |
<td>ON</td> | |
<td>OFF</td> | |
<td>Use</td> | |
<td>Active?</td> | |
<td>Pin</td> | |
</tr> | |
</thead> | |
<form action="./updategpio" id="form1"> | |
<tr> | |
<td>1</td> | |
<td><input type="radio" id="channel_1_on" name="channel_1" value=1{" checked" if bool(int(gpiodict["channel_1"]["active"])) else ""}></td> | |
<td><input type="radio" id="channel_1_off" name="channel_1" value=0{" checked" if not bool(int(gpiodict["channel_1"]["active"])) else ""}></td> | |
<td id="chan1_desc">PSU</td> | |
<td id="chan1_status">{bool(int(gpiodict["channel_1"]["active"]))}</td> | |
<td>{gpiodict["channel_1"]["pin"]}</td> | |
</tr> | |
<tr> | |
<td>2</td> | |
<td><input type="radio" id="channel_2_on" name="channel_2" value=1{" checked" if bool(int(gpiodict["channel_2"]["active"])) else ""}></td> | |
<td><input type="radio" id="channel_2_off" name="channel_2" value=0{" checked" if not bool(int(gpiodict["channel_2"]["active"])) else ""}></td> | |
<td id="chan2_desc">Lights</td> | |
<td id="chan2_status">{bool(int(gpiodict["channel_2"]["active"]))}</td> | |
<td>{gpiodict["channel_2"]["pin"]}</td> | |
</tr> | |
<tr> | |
<td>3</td> | |
<td><input type="radio" id="channel_3_on" name="channel_3" value=1{" checked" if bool(int(gpiodict["channel_3"]["active"])) else ""}></td> | |
<td><input type="radio" id="channel_3_off" name="channel_3" value=0{" checked" if not bool(int(gpiodict["channel_3"]["active"])) else ""}></td> | |
<td id="chan3_desc">Enviro Indoor</td> | |
<td id="chan3_status">{bool(int(gpiodict["channel_3"]["active"]))}</td> | |
<td>{gpiodict["channel_3"]["pin"]}</td> | |
</tr> | |
<tr> | |
<td>4</td> | |
<td><input type="radio" id="channel_4_on" name="channel_4" value=1{" checked" if bool(int(gpiodict["channel_4"]["active"])) else ""}></td> | |
<td><input type="radio" id="channel_4_off" name="channel_4" value=0{" checked" if not bool(int(gpiodict["channel_4"]["active"])) else ""}></td> | |
<td id="chan4_desc">Empty</td> | |
<td id="chan4_status">{bool(int(gpiodict["channel_4"]["active"]))}</td> | |
<td>{gpiodict["channel_4"]["pin"]}</td> | |
</tr> | |
<tr> | |
<td>5</td> | |
<td><input type="radio" id="channel_5_on" name="channel_5" value=1{" checked" if bool(int(gpiodict["channel_5"]["active"])) else ""}></td> | |
<td><input type="radio" id="channel_5_off" name="channel_5" value=0{" checked" if not bool(int(gpiodict["channel_5"]["active"])) else ""}></td> | |
<td id="chan5_desc">Empty</td> | |
<td id="chan5_status">{bool(int(gpiodict["channel_5"]["active"]))}</td> | |
<td>{gpiodict["channel_5"]["pin"]}</td> | |
</tr> | |
<tr> | |
<td>6</td> | |
<td><input type="radio" id="channel_6_on" name="channel_6" value=1{" checked" if bool(int(gpiodict["channel_6"]["active"])) else ""}></td> | |
<td><input type="radio" id="channel_6_off" name="channel_6" value=0{" checked" if not bool(int(gpiodict["channel_6"]["active"])) else ""}></td> | |
<td id="chan6_desc">Empty</td> | |
<td id="chan6_status">{bool(int(gpiodict["channel_6"]["active"]))}</td> | |
<td>{gpiodict["channel_6"]["pin"]}</td> | |
</tr> | |
<tr> | |
<td>7</td> | |
<td><input type="radio" id="channel_7_on" name="channel_7" value=1{" checked" if bool(int(gpiodict["channel_7"]["active"])) else ""}></td> | |
<td><input type="radio" id="channel_7_off" name="channel_7" value=0{" checked" if not bool(int(gpiodict["channel_7"]["active"])) else ""}></td> | |
<td id="chan7_desc">Empty</td> | |
<td id="chan7_status">{bool(int(gpiodict["channel_7"]["active"]))}</td> | |
<td>{gpiodict["channel_7"]["pin"]}</td> | |
</tr> | |
<tr> | |
<td>8</td> | |
<td><input type="radio" id="channel_8_on" name="channel_8" value=1{" checked" if bool(int(gpiodict["channel_8"]["active"])) else ""}></td> | |
<td><input type="radio" id="channel_8_off" name="channel_8" value=0{" checked" if not bool(int(gpiodict["channel_8"]["active"])) else ""}></td> | |
<td id="chan8_desc">Empty</td> | |
<td id="chan8_status">{bool(int(gpiodict["channel_8"]["active"]))}</td> | |
<td>{gpiodict["channel_8"]["pin"]}</td> | |
</tr> | |
</form> | |
</table> | |
<input type="submit" value="Submit" form="form1"> | |
</body> | |
</html>""" | |
return str(html) | |
def serve(connection): | |
#Start a web server | |
while True: | |
gpios, pins = generate_pins_and_gpios() | |
client = connection.accept()[0] | |
request = client.recv(1024) | |
request = str(request) | |
try: | |
request = request.split()[1] | |
except IndexError: | |
pass | |
if "updategpio?" in request: | |
gpios, pins = handle_gpio_update(request, gpios, pins) | |
html = webpage(gpios) | |
client.send(html) | |
client.close() | |
def handle_gpio_update(request, gpios, pins): | |
#Get new value states and update accordingly | |
reqsplit = [_.split("=") for _ in request.split("updategpio?")[-1].split(" ")[0].split("&")] | |
vars = {i: j for i, j in reqsplit} # {channel_1: 1, channel_2: 0} | |
for chan, val in vars.items(): | |
pins[chan].value(int(val)) # set value | |
gpios[chan]["active"] = val # save config | |
with open("channels.json", "wb") as afile: # write config | |
json.dump(gpios, afile) | |
return gpios, pins | |
def generate_pins_and_gpios(): | |
#Generate Pin objects, GPIO values | |
with open("channels.json", "rb") as afile: | |
gpios = json.load(afile) | |
pins = {gpio: machine.Pin(int(gpios[gpio]["pin"]), machine.Pin.OUT, value=int(gpios[gpio]["active"])) for gpio in gpios} | |
return gpios, pins | |
def notification_pinsetup(): | |
#Prepare beep, onboard LED, RGB LED | |
buzzer = Buzzer(880) | |
led_onboard = machine.Pin("LED", machine.Pin.OUT) | |
led_rgb = neopixel.NeoPixel(machine.Pin(13), 1) | |
return buzzer, led_onboard, led_rgb | |
def intro_notifications(buzzer, led_onboard, led_rgb): | |
#Beep, onboard LED, RGB LED | |
led_onboard.on() | |
buzzer.beep(0.5) | |
led_rgb.fill((0,8,0)) # R=0, G=8, B=0 | |
led_rgb.write() | |
def main(): | |
#Start it up! | |
try: | |
buzzer, led_onboard, led_rgb = notification_pinsetup() | |
try: | |
os.stat("channels.json") | |
except OSError: | |
write_default_json() | |
try: | |
os.stat("secrets.json") | |
except OSError: | |
write_default_secrets() | |
ip = connect() | |
intro_notifications(buzzer, led_onboard, led_rgb) # fire when connection established | |
connection = open_socket(ip) | |
serve(connection) | |
except KeyboardInterrupt: | |
machine.reset() | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment