Raspberry pi pico projekt #3 - lámpa kapcsoló

írta: saja, 7 hónapja

Van egy fali lámpa a nappaliban. 2x3w meleg fehér LED, hygge fényt ad. Felújításnál raktuk fel, volt kilógó föld, nulla és fázis, közelben a bejárati ajtó mellett kapcsoló (gondoltuk azt kapcsolja). Közben derült ki, hogy a vezeték csak simán konnektorból lett felvezetve, nincs hozzá kapcsoló. Egyébként is rossz helyen lett volna hozzá a bejárati ajtó mellett, nem lett volna kényelmes.
Kanapé került alá, és nem akartunk fizikai kapcsolót rakni oda a falra esztétikai okok miatt. Szóval kaptam kollégámtól egy shelly wifi-s kapcsolót, amit be lehetett rakni a falba (pont befért a kanapé mögötti, alatta lévő konnektor mögé.

Hamar kiderült, hogy kényelmetlen mindig laptop-on vagy telefonon (akár a saját applikációval) kapcsolgatni, amikor kell. Egy fizikai kapcsoló kell! Ekkor már volt nálam pár pico w egység. Adta magát a dolog: abból lesz a vezeték nélküli villanykapcsoló. Ám nem elégedtem volna meg azzal, hogy csak a lámpa kapcsolására használjam el. Annyi mindent tud! Szóval raktam hozzá még egy hőmérséklet és páratartalom mérő szenzort is.

Igyekeztem minél egyszerűbben megoldani a dolgot, szerencsére belefért egy szenzor dobozba az egész.

S így néz ki összerakva:

A pico egy egyszerű kis http szervert futtat, ami JSON-ban adja vissza a hőmérséklet és páratartalom értékeket, amint egy http get request érkezik a saját IP címére.
Elkezdtem egy saját szenzor kezelő szerver kódot is írni, amit egy raspberry pi-on futtatok. Annak a lokális IP címét lehet látni a netman modulban. Később ha akarom, akkor még jobban elvonatkoztatva, generálisabb (statikus, konstans beégetett IP cím mellőzésével) kódot is írok. Itthonra ez megfelelő. A dht11 kódját az előző (gyerekszoba lámpa) bejegyzésnél találjátok meg.

Ez már nem tudom hányadik verzió, de valamikor észrevettem, hogy a pico elveszti egy idő után a wifi kapcsolatot és nem csatlakozik vissza. Szóval úgy módosítottam, hogy a listenButtonAndCheckConnection aszinkron metódus óránként meghívja a checkConnection függvényt, amivel leellenőrzi a kapcsolatot és ha kell, visszacsatlakozik.

A következő sorokban a forráskódok lesznek beillesztve.
Itt van a main.py:
import netman
import urequests as requests
import uasyncio as asyncio
import dht11
from machine import Pin

print(asyncio.__version__)

led = Pin("LED", Pin.OUT)
button = Pin(14, Pin.IN, Pin.PULL_DOWN)
shellyIP = '192.168.0.140'

def turnOffLamp():
switch_lamp = 'http://' + shellyIP + '/relay/0?turn=off'
try:
resp = requests.get(switch_lamp)
resp.close()
except:
led.on()

country = 'HU'
ssid = *****
password = *****
wlan = netman.connectWifi(ssid,password,country)

async def listenButtonAndCheckConnection():
button_state = button.value()
switch_lamp = ''
lamp_state = 'off'
count = 0
while True:
if count > 3600000:
await netman.checkConnection(wlan,ssid,password,country)
count = 0
if button_state == 1 and lamp_state == 'on':
print("button clicked to turn off lamp")
lamp_state = 'off'
turnOffLamp()
await asyncio.sleep_ms(20)
button_state = button.value()

if button_state == 1 and lamp_state == 'off':
print("button clicked to turn on lamp")
lamp_state = 'on'
switch_lamp = 'http://' + shellyIP + '/relay/0?turn=on'
try:
resp = requests.get(switch_lamp)
resp.close()
except:
led.on()
await asyncio.sleep_ms(20)

button_state = button.value()
await asyncio.sleep_ms(20)
count += 20

temp_humidity = dht11.getTemp()
json = """{temp: %s, humidity: %s}"""

async def serve(reader, writer):
print("create temperature data to serve")
data = """none"""
try:
temp_humidity = dht11.getTemp()
data = json % temp_humidity
except:
data = """undefined"""
resp = b"HTTP/1.0 200 OK\r\nContent-type: application/json\r\n\r\n" + "{JSON}\r\n".format(JSON=data)
l = await reader.read(256)
print(l)
led.on()
await writer.awrite(resp)
await asyncio.sleep_ms(200)
await writer.wait_closed()
led.off()

print("start event loop")
loop = asyncio.get_event_loop()
loop.create_task(asyncio.start_server(serve, "0.0.0.0", 80))
loop.create_task(listenButtonAndCheckConnection())

try:
loop.run_forever()
except KeyboardInterrupt:
print("closing")
loop.close()

Ez pedig a netman.py:
import network, rp2
import time
import urequests as requests
import uasyncio as asyncio

async def sendIP(connection):
rpi_ip = "192.168.0.170"
print( 'ip = ' + connection[0] )
send_ip = "http://" + str(rpi_ip) + "/cgi-bin/assign.py?sensor2=" + str(connection[0])
success = True
try:
resp = requests.get(send_ip)
resp.close()
except:
success = False
print("couldn't send own IP address")
asyncio.sleep_ms(200)
return success

def initWLAN(ssid,password,country):
print("initializing WLAN connection...")
rp2.country(country)
wlan = network.WLAN(network.STA_IF)
wlan.config(pm = 0xa11140)
wlan.active(True)
wlan.connect(ssid,password)
# Wait for connect or fail
max_wait = 10
while max_wait > 0:
if wlan.status() < 0 or wlan.status() >= 3:
break
max_wait -= 1
print('waiting for connection...')
time.sleep(1)
return wlan

def tryToConnect(ssid,password,country):
status = 0
retry = 0
n = 1
while status != 3 and retry < 20:
n += retry
retry = n - retry
try:
wlan = initWLAN(ssid,password,country)
status = wlan.status()
except:
print('no network connection')
time.sleep(int(retry))
if status != 3 and retry >= 20:
raise RuntimeError('network connection failed')
else:
print('connected')
return wlan

def connectWifi(ssid,password,country):
print("trying connection")
wlan = tryToConnect(ssid,password,country)
return wlan

async def checkConnection(wlan,ssid,password,country):
IPSent = await sendIP(wlan.ifconfig())
if wlan.status() != 3:
print("connection lost")
wlan = tryToConnect(ssid,password,country)
await asyncio.sleep(3600)
if IPSent == False:
print("can't assign IP to rpi server")
IPSent = await sendIP(wlan.ifconfig())
await asyncio.sleep(10)