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

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)

Hirdetés

3 pénzügyi döntés, amit minden kisvállalkozónak érdemes átgondolnia az év végéig

PR Ahogy az év vége közeledik, itt az ideje, hogy egy pillanatra megálljunk és áttekintsük vállalkozásunk pénzügyi helyzetét. Ne hagyjuk, hogy az év utolsó hónapjai elússzanak a sürgető feladatok és elfeledett határidők között!

  • saja

    csendes tag

    Változtattam a kódon. Nincs benne órás várakozás, és a gomb figyelést egy másik szálon végzem, a kapcsolati ellenőrzés pedig "szinkron" működik. Előtte pedig még le is kérem a shelly kapcsoló relé státuszát (tehát nem kell mondjuk kétszer nyomni a gombot, hogy lekapcsolja a lámpát ha már fel van kapcsolva).

    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'

    async def blinking():
    while True:
    led.on()
    asyncio.sleep(0.3)
    led.off()
    asyncio.sleep(0.3)

    def toggleLamp(lamp_state):
    print("button clicked to turn " + lamp_state + " lamp")
    switch_lamp = 'http://' + shellyIP + '/relay/0?turn=' + lamp_state
    blink_task = asyncio.create_task(blinking())
    try:
    resp = requests.get(switch_lamp)
    resp.close()
    blink_task.cancel()
    except:
    blink_task.cancel()
    led.on()

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

    async def listenButton(defaultLampState):
    button_state = button.value()
    switch_lamp = ''
    lamp_state = defaultLampState
    count = 0
    while True:
    if button_state == 1 and lamp_state == 'on':
    lamp_state = 'off'
    toggleLamp(lamp_state)
    await asyncio.sleep_ms(200)
    button_state = button.value()

    if button_state == 1 and lamp_state == 'off':
    lamp_state = 'on'
    toggleLamp(lamp_state)
    await asyncio.sleep_ms(200)
    button_state = button.value()
    await asyncio.sleep_ms(200)

    async def listenButtonAndCheckConnection():
    wlan_next = netman.checkConnection(wlan,ssid,password,country)
    defaultLampState = 'off'
    try:
    resp = requests.get('http://' + shellyIP + '/relay/0')
    print(resp.text)
    parsedResp = resp.json()
    print(parsedResp["ison"])
    if parsedResp["ison"] == True:
    defaultLampState = 'on'
    resp.close()
    except:
    print("couldn't fetch shelly relay status")
    asyncio.create_task(listenButton(defaultLampState))
    while True:
    await asyncio.sleep(1)
    wlan_next = netman.checkConnection(wlan_next,ssid,password,country)

    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()

    A netman.py kódját is kicsit alakítottam. Az ellenőrző függvény máshogy néz ki:
    def checkConnection(wlan,ssid,password,country):
    status = wlan.status()
    print(status)
    if status != 3:
    print("connection lost")
    wlan = tryToConnect(ssid,password,country)
    return wlan
    else:
    print("connection ok")
    time.sleep(0.2)
    return wlan

  • DEJVID

    őstag

    válasz UnA #4 üzenetére

    Konkrétan a python syntaxot nem szeretem. Változó típusok, access modifierek és {} jelek hiánya nekem nagyon zavaró :D

  • UnA

    Korrektor

    válasz DEJVID #2 üzenetére

    Nem lehet, hogy csak mobilon nézted? A logoutos mobil nézet nem tudja a "code" jellegű formázást, vagyis nincs indent és coloring. Így minden programkód elég nehezen értelmezhető.

    Persze az is lehetséges, hogy nem kedveled a Pythont :)

  • saja

    csendes tag

    Az egyik előző projektet amúgy is Erlang-ban tervezem átírni ;) . (Vagy c++ nyelven, pico sdk-val)

  • BigBlackDog

    veterán

    Ötletes!

    Ha amiatt dobálja el a Wifit, mert régóta már fel van csatlakozva, akkor esetleg én annyival módosítanám, hogy óránként nem csak szükség esetén csatlakoznék fel a wifire, hanem mindenképpen bontanám és kiépíteném újra a kapcsolatot. Így mindig viszonylag "friss" a Wifi kapcsolat. Egyéb esetben, hiába van óránként ellenőrzés, megeshet, hogy szélsőséges esetben akár egy órát is offline az eszköz és csak ezután fog az ütemezett újracsatlakozás futni.

Tovább a fórumba.