Skip to content

Instantly share code, notes, and snippets.

@thurask
Last active June 26, 2023 22:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thurask/ecd9e4390f4c5e0948fa38ea80ddf6a2 to your computer and use it in GitHub Desktop.
Save thurask/ecd9e4390f4c5e0948fa38ea80ddf6a2 to your computer and use it in GitHub Desktop.
Waveshare Pico Relay board web server for Pico W MicroPython
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