2024. március 2., szombat

Gyorskeresés

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

Írta: | Kulcsszavak: pi pico . DIY

[ ÚJ BEJEGYZÉS ]

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)

Hozzászólások

(#1) BigBlackDog


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.

(#2) DEJVID


DEJVID
őstag

Hú de nem szeretek pythont olvasni :D

(#3) saja


saja
tag

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

keep calm and code erlang

(#4) UnA válasza DEJVID (#2) üzenetére


UnA
Korrektor

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

(#5) DEJVID válasza UnA (#4) üzenetére


DEJVID
őstag

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

(#6) saja


saja
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

[ Szerkesztve ]

keep calm and code erlang

További hozzászólások megtekintése...
Copyright © 2000-2024 PROHARDVER Informatikai Kft.