![ESP32 Управление на Лампа с MicroPython и Wi-Fi Свързаност](http://ardudevelop.eu/wp-content/uploads/2024/08/ESP32-Управление-на-Лампа-с-MicroPython-и-Wi-Fi-Свързаност.png)
Въведение
Проектът представя интелигентна система за управление на лампа, базирана на ESP32 микроконтролер, използващ езика за програмиране MicroPython. Системата предоставя възможност за контрол чрез бутон, сензор за движение (PIR), и уеб интерфейс, достъпен чрез Wi-Fi връзка. Допълнителните функции включват показване на температура и влажност на въздуха посредством DHT22 сензор и използването на I2C LCD дисплей за визуализация на данните. В тази статия ще разгледаме основните компоненти и функционалности на проекта.
Конфигурация на мрежата и свързаност (boot.py)
Файлът boot.py
е отговорен за първоначалната конфигурация на Wi-Fi свързаността на устройството. В него се използва библиотеката network
, за да се установи връзка с безжична мрежа. Основните стъпки включват активиране на Wi-Fi модула, сканиране на наличните мрежи и опит за свързване към зададената Wi-Fi мрежа. В случай на успешна връзка, в конзолата се отпечатва IP адресът на устройството, което позволява последващото му използване в мрежата.
Кодът за boot.py
:
import network
from time import sleep
import esp
esp.osdebug(None)
sta_if = network.WLAN(network.STA_IF);
sta_if.active(True)
sta_if.scan() # Сканиране на налични WiFi мрежи
try:
sta_if.connect("SSID", "PASSWORD") # Въведете вашето Име и Парола на WiFi
except OSError as error:
print(error, ": The wifi as already connect")
while sta_if.isconnected() == False:
print("unible to connrct to WiFi")
sleep(0.5)
if sta_if.isconnected() == True: # Check for successful connection
print("connect sucsess")
print("IP address = " , sta_if.ifconfig()[0])
else:
print("WiFi is not connrct")
import webrepl
webrepl.start()
Основен код и функционалности (main.py)
Файлът main.py
съдържа основната логика на устройството и използва множество библиотеки за управление на различните периферии. Кодът е структуриран в две основни части: функция за уеб сървър, която се изпълнява на второ ядро (Core 1), и основната логика на устройството, която се изпълнява на основното ядро (Core 0).
Кодът за main.py
:
import _thread
import uasyncio as asyncio
from time import sleep
from machine import Pin, SoftI2C
from ds3231 import DS3231
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
import dht
import network
try:
import usocket as socket
except:
import socket
import gc
gc.collect()
#====================================================================
Led_Status_Core_1 = Pin(2, Pin.OUT)
Led_Status_Core_1.off()
button = Pin(15, Pin.IN)
button_push_count = 0
web_switch = 0
PIR = Pin(26, Pin.IN, Pin.PULL_DOWN)
PIR_active = 0
PIR_timer_stop = 10 # задаване на времето в което PIR проверява дали има актовност в стаята!
relay = Pin(13, Pin.OUT)
relay.off()
relay_logic_state = 0
i2c = SoftI2C(sda=Pin(21), scl=Pin(22), freq=400000)
dht_inicialize = dht.DHT22(Pin(25))
temperature = 0.0
humidity = 0.0
I2C_ADDR = 0x27
totalRows = 4 # брой редове на LCD
totalColumns = 20 # дължина на реда на LCD
lcd = I2cLcd(i2c, I2C_ADDR, totalRows, totalColumns)
ds3231_year = ""
ds3231_time = ""
#print("IP address = " , sta_if.ifconfig()[0])
#====================================================================
#-----/ Core 1 function\------
def Core_1_function():
def web_page():
global button_push_count
global PIR_active
global web_switch
if button_push_count == 1:
gpio_state="Light ON"
if button_push_count == 0:
gpio_state="Light OFF"
if button_push_count == 2:
gpio_state="PIR activate"
html = """
<html>
<head>
<title>Hall Light Control</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="refresh" content="3;url=http://192.168.100.132">
<meta charset="UTF-8">
<link rel="icon" href="data:,">
<style>
html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
h1{color: #0F3376; padding: 2vh;}
p{font-size: 1.5rem;}
.button{display: inline-block; background-color: cyan; border: none;
border-radius: 4px; color: black; padding: 16px 40px;
text-decoration: none;
font-size: 30px;
margin: 2px;
cursor: pointer;}
</style>
</head>
<body>
<h1>Light control in the living room</h1>
<p>Дата : """ + ds3231_year + """ Час : """ + ds3231_time + """</p><br>
<p>
<a href="/?switch"><button class="button">Switch Function</button></a>
<br>
<strong>""" + gpio_state + """</strong>
</p><hr><br>
<p>Температура : """ + str(temperature) + """ *C</p>
<p>Влажност : """ + str(humidity) + """ %</p>
</body>
</html>
"""
return html
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)
while True:
global button_push_count
global web_switch
conn, addr = s.accept()
#print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
request = str(request)
#print('Content = %s' % request)
#-----// relay 1 \\------
switch = request.find('/?switch')
if switch == 6:
#print('switch')
web_switch = 1
response = web_page()
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.sendall(response)
conn.close()
#-----/ Core 1 START\------
_thread.start_new_thread(Core_1_function, ())
#====================================================================
#-----/ Core 0 \------
while True:
#================================== СТАТУС Core-0 (prime)
async def status_led_Core_1():
while True:
Led_Status_Core_1.on()
await asyncio.sleep_ms(500)
Led_Status_Core_1.off()
await asyncio.sleep_ms(500)
#================================== READ DHT22 (temp,hum)
async def dht_read():
global temperature
global humidity
while True:
dht_inicialize.measure()
temperature = dht_inicialize.temperature()
temperature = round(temperature , 1)
humidity = dht_inicialize.humidity()
humidity = round(humidity , 1)
#print("temp = " , temperature)
#print("hum = " , humidity)
await asyncio.sleep(2)
#================================== DS3231 RTC
async def read_DS3231():
while True:
ds = DS3231(i2c) # изчитане на показанията от DS3231 RTC
#print(ds.datetime())
global ds3231_year
global ds3231_time
ds3231_year = str(ds.datetime()[2]) + ":" + str(ds.datetime()[1]) + ":" + str(ds.datetime()[0])
"""ds3231_time = str(ds.datetime()[4]) + ":" + str(ds.datetime()[5]) + ":" + str(ds.datetime()[6])"""
ds3231_time = str(ds.datetime()[4]) + ":" + str(ds.datetime()[5])
#print(ds3231_year, ds3231_time)
await asyncio.sleep_ms(10000)
#================================== LCD WRITE TIME
async def write_time_to_LCD():
while True:
lcd.move_to(0 , 0)
lcd.putstr(ds3231_year + "/" + ds3231_time)
await asyncio.sleep(30)
lcd.clear_line(0) # изтрива само първи ред
#================================== LCD WRITE temperature
async def write_temp_to_LCD():
while True:
lcd.move_to(0 , 2)
lcd.putstr("Temp = " + str(temperature) + " *C")
await asyncio.sleep(40)
lcd.clear_line(2) # изтрива трети ред
#================================== LCD WRITE humidity
async def write_hum_to_LCD():
while True:
lcd.move_to(0 , 3)
lcd.putstr("Humi = " + str(humidity) + " %")
#print(humidity)
await asyncio.sleep(45)
lcd.clear_line(3) # изтрива четвърти ред
#================================== LCD WRITE управление от BUTTON, PIR or RELAY off
async def write_control_to_LCD():
global relay_logic_state
global PIR_active
while True:
if relay_logic_state == 0:
lcd.move_to(0 , 1)
lcd.putstr(" Lamp OFF")
if relay_logic_state == 1:
lcd.move_to(0 , 1)
lcd.putstr(" Lamp ON ")
if PIR_active == 1:
lcd.move_to(0 , 1)
lcd.putstr(" PIR-Activ")
await asyncio.sleep(1.7)
lcd.clear_line(1) # изтрива втори ред
#================================== БУТОН on/off
async def button_read():
global relay_logic_state
global PIR_active
global button_push_count
global web_switch
while True:
button_logic_state = button.value()
if button_logic_state == 0 or web_switch == 1:
button_push_count += 1
#print("cout = " , button_push_count)
if button_push_count == 1:
relay_logic_state = 1
PIR_active = 0 # деактивиране на PIR
web_switch = 0
await asyncio.sleep_ms(200)
if button_push_count == 2:
# relay_logic_state = 0 # може би ако го деактивирам от тук ще при всеки цикъл ще казва че релето е OFF
PIR_active = 1 # активиране на PIR
#button_push_count = 0
web_switch = 0
await asyncio.sleep_ms(200)
if button_push_count == 3:
relay_logic_state = 0
PIR_active = 0 # деактивиране на PIR
button_push_count = 0
web_switch = 0
await asyncio.sleep_ms(200)
await asyncio.sleep_ms(100)
#================================== PIR check is on/off
def check_pir():
return PIR.value()
#================================== PIR on/off relay
async def PIR_control():
global PIR_active
global PIR_timer_stop
global relay_logic_state
while True:
if PIR_active == 1:
if check_pir() == 1:
i = 0
while i <= PIR_timer_stop:
#print("i = " , i)
relay_logic_state = 1
if check_pir() == 1:
i = 0
await asyncio.sleep(1)
i += 1
if PIR_active == 0: # терминира цикъла от бутона
relay_logic_state = 0
break
if check_pir() == 0:
relay_logic_state = 0
await asyncio.sleep_ms(100)
#================================== RELAY on/off
async def relay_state():
global relay_logic_state
while True:
if relay_logic_state == 1:
relay.on()
#print("lamp on")
if relay_logic_state == 0:
relay.off()
#print("lamp off")
await asyncio.sleep_ms(500)
#================================== Стартиране на tasks...
async def main():
task1 = asyncio.create_task(read_DS3231())
task2 = asyncio.create_task(write_time_to_LCD())
task3 = asyncio.create_task(status_led_Core_1())
task4 = asyncio.create_task(button_read())
task5 = asyncio.create_task(relay_state())
task6 = asyncio.create_task(dht_read())
task6 = asyncio.create_task(write_temp_to_LCD())
task7 = asyncio.create_task(write_hum_to_LCD())
task8 = asyncio.create_task(PIR_control())
task9 = asyncio.create_task(write_control_to_LCD())
await asyncio.gather(task1, task2, task3, task4, task5, task6, task7, task8, task9)
asyncio.run(main())
Импортиране на библитеки
Тази част от кода включва импортирането на различни библиотеки и модули, които осигуряват функционалността, необходима за управление на проекта с ESP32. Ето какво прави всяка от тях:
import _thread
import uasyncio as asyncio
from time import sleep
from machine import Pin, SoftI2C
from ds3231 import DS3231
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
import dht
import network
try:
import usocket as socket
except:
import socket
import gc
gc.collect()
- _thread: Този модул позволява създаването на нови потоци за паралелно изпълнение на функции. В случая се използва за стартиране на функция на второто ядро на ESP32.
- uasyncio като asyncio: Модулът
uasyncio
е MicroPython версия на популярната библиотекаasyncio
от Python, която осигурява асинхронно програмиране. Тя позволява изпълнението на задачи едновременно, като същевременно се използва малко памет и процесорни ресурси. - from time import sleep: Функцията
sleep
от модулаtime
позволява паузирането на изпълнението на програмата за определен период от време. - from machine import Pin, SoftI2C: Модулът
machine
предоставя функции за работа с хардуерни компоненти.Pin
се използва за контрол на GPIO пиновете на ESP32, аSoftI2C
е софтуерна имплементация на I2C комуникационния протокол. - from ds3231 import DS3231: Този модул позволява комуникацията с DS3231 – модул за реално време (RTC), който осигурява точни часови данни. Може да свалите боблиотеката от тук.
- from lcd_api import LcdApi и from i2c_lcd import I2cLcd: Тези модули осигуряват интерфейс за управление на LCD дисплеи чрез I2C протокол.
LcdApi
е основният API за управление на дисплея, докатоI2cLcd
е специфична имплементация за работа с I2C LCD дисплеи. Тези библиотеки може да свалите от тук. - import dht: Този модул се използва за работа със сензори за температура и влажност DHT (например DHT22), които предоставят данни за околната среда.
- import network: Модулът
network
позволява на ESP32 да се свързва с Wi-Fi мрежи и да осъществява мрежова комуникация. - import usocket като socket:
usocket
е MicroPython версия на стандартнияsocket
модул, който осигурява възможности за мрежова комуникация чрез създаване на TCP/UDP връзки. - import gc и gc.collect(): Модулът
gc
(garbage collector) се използва за управление на паметта, като функциятаcollect()
се използва за освобождаване на неизползвана памет, за да се предотврати изчерпването ѝ и да се поддържа плавното изпълнение на програмата.
Инициализация и конфигурация на хардуера
Тази част от кода инициализира и конфигурира различни хардуерни компоненти на ESP32 микроконтролера, които ще се използват в проекта за управление на лампа чрез PIR сензор, бутон и Wi-Fi свързаност. Запознайте се с ESP32 платформата в нашата страница ESP32 Wroom 30/38 pins.
Ето подробно обяснение на всеки ред от кода:
Led_Status_Core_1 = Pin(2, Pin.OUT)
Led_Status_Core_1.off()
button = Pin(15, Pin.IN)
button_push_count = 0
web_switch = 0
PIR = Pin(26, Pin.IN, Pin.PULL_DOWN)
PIR_active = 0
PIR_timer_stop = 10 # задаване на времето в което PIR проверява дали има актовност в стаята!
relay = Pin(13, Pin.OUT)
relay.off()
relay_logic_state = 0
i2c = SoftI2C(sda=Pin(21), scl=Pin(22), freq=400000)
dht_inicialize = dht.DHT22(Pin(25))
temperature = 0.0
humidity = 0.0
I2C_ADDR = 0x27
totalRows = 4 # брой редове на LCD
totalColumns = 20 # дължина на реда на LCD
lcd = I2cLcd(i2c, I2C_ADDR, totalRows, totalColumns)
ds3231_year = ""
ds3231_time = ""
Led_Status_Core_1 = Pin(2, Pin.OUT)
Този ред създава обектPin
, свързан с GPIO 2 на ESP32, който е настроен като изход (Pin.OUT
). Това ще бъде използвано за управление на LED, който показва статуса на Core 1.Led_Status_Core_1.off()
Този ред изключва LED-а, като задава ниско ниво на GPIO 2, което спира подаването на напрежение към него.button = Pin(15, Pin.IN)
Тук се създава обектPin
, свързан с GPIO 15, който е настроен като вход (Pin.IN
). Този пин ще бъде използван за четене на състоянието на бутон, свързан към него.button_push_count = 0
Този ред инициализира брояч на натискания на бутона. Започва от нула и ще се увеличава всеки път, когато бутонът бъде натиснат.web_switch = 0
Инициализира се променливаweb_switch
, която ще се използва за управление на лампата чрез уеб интерфейс. Стойността ѝ ще бъде променяна при заявки от уеб страницата.PIR = Pin(26, Pin.IN, Pin.PULL_DOWN)
Този ред създава обектPin
, свързан с GPIO 26, който е настроен като вход с пулдаун резистор (Pin.PULL_DOWN
). Това означава, че ако няма активност на пина, стойността му ще бъде държана на ниско ниво. Този пин е свързан към PIR (Passive Infrared) сензор, който ще се използва за откриване на движение.PIR_active = 0
Тази променлива указва дали PIR сензорът е активен. В началото е инициализирана със стойност 0 (неактивен).PIR_timer_stop = 10 # задаване на времето в което PIR проверява дали има актовност в стаята!
Този ред задава времето (в секунди), през което PIR сензорът ще проверява за активност в стаята. Ако няма движение за това време, лампата ще се изключи.relay = Pin(13, Pin.OUT)
Тук се създава обектPin
, свързан с GPIO 13, който е настроен като изход (Pin.OUT
). Този пин е свързан към релето, което ще управлява включването и изключването на лампата.relay.off()
Този ред изключва релето, като задава ниско ниво на GPIO 13, което означава, че лампата е изключена.relay_logic_state = 0
Тази променлива съхранява състоянието на релето – дали лампата е включена (1) или изключена (0).i2c = SoftI2C(sda=Pin(21), scl=Pin(22), freq=400000)
Този ред инициализира софтуерен I2C интерфейс с използване на GPIO 21 за SDA (Serial Data Line) и GPIO 22 за SCL (Serial Clock Line). Честотата на комуникация е зададена на 400 kHz. Този I2C интерфейс ще бъде използван за комуникация с различни периферни устройства, като DHT сензора и LCD екрана.dht_inicialize = dht.DHT22(Pin(25))
Тук се инициализира DHT22 сензор за измерване на температура и влажност, който е свързан към GPIO 25.temperature = 0.0
иhumidity = 0.0
Тези променливи съхраняват текущите стойности на температурата и влажността, измерени от DHT22 сензора. В началото те са инициализирани на 0.0.I2C_ADDR = 0x27
Този ред задава I2C адреса на LCD дисплея, който е свързан към микроконтролера.totalRows = 4
иtotalColumns = 20
Тези променливи указват броя на редовете и колоните на LCD дисплея. В този случай, дисплеят има 4 реда и 20 колони.lcd = I2cLcd(i2c, I2C_ADDR, totalRows, totalColumns)
Тук се създава обектI2cLcd
, който управлява LCD дисплея чрез I2C интерфейса. Този обект ще бъде използван за писане на информация на дисплея.ds3231_year = ""
иds3231_time = ""
Тези променливи ще съхраняват текущата дата и час, прочетени от DS3231 RTC модула (Real-Time Clock).
Тази инициализация създава основната структура за работа с хардуерните компоненти, които ще се използват за управление на осветлението в стаята, базирано на входове от бутона и PIR сензора, както и за показване на информация на LCD дисплея.
ESP32 Core 1
Тази част от кода реализира уеб сървър на ESP32, който позволява управление на лампа чрез уеб интерфейс. Функцията Core_1_function
се изпълнява на второто ядро (Core 1) на ESP32, което освобождава основното ядро (Core 0) за изпълнение на други задачи, като мониторинг на сензори и управление на хардуерни изходи.
#-----/ Core 1 function\------
def Core_1_function():
def web_page():
global button_push_count
global PIR_active
global web_switch
if button_push_count == 1:
gpio_state="Light ON"
if button_push_count == 0:
gpio_state="Light OFF"
if button_push_count == 2:
gpio_state="PIR activate"
html = """
<html>
<head>
<title>Hall Light Control</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="refresh" content="3;url=http://192.168.100.132">
<meta charset="UTF-8">
<link rel="icon" href="data:,">
<style>
html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
h1{color: #0F3376; padding: 2vh;}
p{font-size: 1.5rem;}
.button{display: inline-block; background-color: cyan; border: none;
border-radius: 4px; color: black; padding: 16px 40px;
text-decoration: none;
font-size: 30px;
margin: 2px;
cursor: pointer;}
</style>
</head>
<body>
<h1>Light control in the living room</h1>
<p>Дата : """ + ds3231_year + """ Час : """ + ds3231_time + """</p><br>
<p>
<a href="/?switch"><button class="button">Switch Function</button></a>
<br>
<strong>""" + gpio_state + """</strong>
</p><hr><br>
<p>Температура : """ + str(temperature) + """ *C</p>
<p>Влажност : """ + str(humidity) + """ %</p>
</body>
</html>
"""
return html
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)
while True:
global button_push_count
global web_switch
conn, addr = s.accept()
#print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
request = str(request)
#print('Content = %s' % request)
#-----// relay 1 \\------
switch = request.find('/?switch')
if switch == 6:
#print('switch')
web_switch = 1
response = web_page()
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.sendall(response)
conn.close()
#-----/ Core 1 START\------
_thread.start_new_thread(Core_1_function, ())
1. Функция Core_1_function
Core_1_function
е основната функция, която се изпълнява на Core 1 и управлява уеб сървъра, позволявайки дистанционно управление на лампата и показване на данни като температура, влажност и време.
2. Функция web_page
Функцията web_page
генерира HTML код за уеб страницата, която се предоставя на клиента (например браузър) при заявка. Страницата показва текущото състояние на лампата, както и показания за температура, влажност и текущо време.
- Глобални променливи:
button_push_count
: Определя броя на натисканията на бутона, който контролира лампата. Тази стойност се използва за определяне на състоянието на лампата.PIR_active
: Указва дали PIR сензорът е активен.web_switch
: Флаг, използван за управление на лампата чрез уеб интерфейса.
- Определяне на състоянието на лампата: В зависимост от стойността на
button_push_count
, се определя състоянието на лампата:- При
button_push_count = 1
, лампата е включена (изписва се “Light ON”). - При
button_push_count = 0
, лампата е изключена (изписва се “Light OFF”). - При
button_push_count = 2
, PIR сензорът е активиран (изписва се “PIR activate”).
- При
- Генериране на HTML страница: HTML кодът, генериран от
web_page
, включва:- Заглавие на страницата и стилове за оформлението.
- Текущата дата и час, получени от DS3231 RTC модула.
- Бутон за превключване на състоянието на лампата.
- Текущото състояние на лампата.
- Показания за температура и влажност, получени от DHT22 сензора.
3. Настройка на сокет сървър
Създава се и конфигурира сокет сървър, който слуша за входящи HTTP заявки на порт 80. Това е стандартният порт за уеб сървъри, което позволява на ESP32 да приема и обработва заявки от мрежата.
- Създаване на сокет:
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
: Създава нов TCP сокет с IPv4.
- Обвързване и слушане:
s.bind(('', 80))
: Сокетът се обвързва с всички налични мрежови интерфейси и слуша на порт 80.s.listen(5)
: Започва да слуша за входящи връзки, като максималният брой чакащи връзки е 5.
4. Основен цикъл за обработка на заявки
В основния цикъл на функцията Core_1_function
се обработват входящите връзки от клиенти (браузъри). Всяка заявка се анализира и се проверява дали съдържа команда за превключване на състоянието на лампата. След това се генерира и изпраща HTML страница с актуалната информация за състоянието на системата.
- Обработка на входящи заявки:
conn, addr = s.accept()
: Приема нова връзка от клиент и създава обектиconn
иaddr
за връзката.request = conn.recv(1024)
: Получава HTTP заявка от клиента.switch = request.find('/?switch')
: Проверява дали заявката съдържа команда за превключване на лампата.
- Управление на лампата чрез уеб интерфейса:
- Ако в заявката се открие
/switch
, променливатаweb_switch
се задава на 1, което сигнализира за промяна в състоянието на лампата.
- Ако в заявката се открие
- Изпращане на отговор:
- Генерираната HTML страница от
web_page
се изпраща обратно на клиента като отговор на заявката.
- Генерираната HTML страница от
5. Стартиране на Core 1 функцията
Функцията Core_1_function
се стартира в нова нишка, използвайки _thread.start_new_thread(Core_1_function, ())
. Това означава, че тя ще работи паралелно с останалите задачи, изпълнявани на основното ядро на ESP32.
ESP32 Core 0 Основна логика на програмата
Тази част от кода реализира основната логика на Core 0 на ESP32, където се изпълняват различни асинхронни задачи. Тези задачи управляват LED индикатор, четат данни от сензори, показват информация на LCD дисплея, и контролират лампата чрез бутон, PIR сензор и реле. Ето подробно обяснение на всяка част от кода:
#-----/ Core 0 \------
while True:
#================================== СТАТУС Core-0 (prime)
async def status_led_Core_1():
while True:
Led_Status_Core_1.on()
await asyncio.sleep_ms(500)
Led_Status_Core_1.off()
await asyncio.sleep_ms(500)
#================================== READ DHT22 (temp,hum)
async def dht_read():
global temperature
global humidity
while True:
dht_inicialize.measure()
temperature = dht_inicialize.temperature()
temperature = round(temperature , 1)
humidity = dht_inicialize.humidity()
humidity = round(humidity , 1)
#print("temp = " , temperature)
#print("hum = " , humidity)
await asyncio.sleep(2)
#================================== DS3231 RTC
async def read_DS3231():
while True:
ds = DS3231(i2c) # изчитане на показанията от DS3231 RTC
#print(ds.datetime())
global ds3231_year
global ds3231_time
ds3231_year = str(ds.datetime()[2]) + ":" + str(ds.datetime()[1]) + ":" + str(ds.datetime()[0])
"""ds3231_time = str(ds.datetime()[4]) + ":" + str(ds.datetime()[5]) + ":" + str(ds.datetime()[6])"""
ds3231_time = str(ds.datetime()[4]) + ":" + str(ds.datetime()[5])
#print(ds3231_year, ds3231_time)
await asyncio.sleep_ms(10000)
#================================== LCD WRITE TIME
async def write_time_to_LCD():
while True:
lcd.move_to(0 , 0)
lcd.putstr(ds3231_year + "/" + ds3231_time)
await asyncio.sleep(30)
lcd.clear_line(0) # изтрива само първи ред
#================================== LCD WRITE temperature
async def write_temp_to_LCD():
while True:
lcd.move_to(0 , 2)
lcd.putstr("Temp = " + str(temperature) + " *C")
await asyncio.sleep(40)
lcd.clear_line(2) # изтрива трети ред
#================================== LCD WRITE humidity
async def write_hum_to_LCD():
while True:
lcd.move_to(0 , 3)
lcd.putstr("Humi = " + str(humidity) + " %")
#print(humidity)
await asyncio.sleep(45)
lcd.clear_line(3) # изтрива четвърти ред
#================================== LCD WRITE управление от BUTTON, PIR or RELAY off
async def write_control_to_LCD():
global relay_logic_state
global PIR_active
while True:
if relay_logic_state == 0:
lcd.move_to(0 , 1)
lcd.putstr(" Lamp OFF")
if relay_logic_state == 1:
lcd.move_to(0 , 1)
lcd.putstr(" Lamp ON ")
if PIR_active == 1:
lcd.move_to(0 , 1)
lcd.putstr(" PIR-Activ")
await asyncio.sleep(1.7)
lcd.clear_line(1) # изтрива втори ред
#================================== БУТОН on/off
async def button_read():
global relay_logic_state
global PIR_active
global button_push_count
global web_switch
while True:
button_logic_state = button.value()
if button_logic_state == 0 or web_switch == 1:
button_push_count += 1
#print("cout = " , button_push_count)
if button_push_count == 1:
relay_logic_state = 1
PIR_active = 0 # деактивиране на PIR
web_switch = 0
await asyncio.sleep_ms(200)
if button_push_count == 2:
# relay_logic_state = 0 # може би ако го деактивирам от тук ще при всеки цикъл ще казва че релето е OFF
PIR_active = 1 # активиране на PIR
#button_push_count = 0
web_switch = 0
await asyncio.sleep_ms(200)
if button_push_count == 3:
relay_logic_state = 0
PIR_active = 0 # деактивиране на PIR
button_push_count = 0
web_switch = 0
await asyncio.sleep_ms(200)
await asyncio.sleep_ms(100)
#================================== PIR check is on/off
def check_pir():
return PIR.value()
#================================== PIR on/off relay
async def PIR_control():
global PIR_active
global PIR_timer_stop
global relay_logic_state
while True:
if PIR_active == 1:
if check_pir() == 1:
i = 0
while i <= PIR_timer_stop:
#print("i = " , i)
relay_logic_state = 1
if check_pir() == 1:
i = 0
await asyncio.sleep(1)
i += 1
if PIR_active == 0: # терминира цикъла от бутона
relay_logic_state = 0
break
if check_pir() == 0:
relay_logic_state = 0
await asyncio.sleep_ms(100)
#================================== RELAY on/off
async def relay_state():
global relay_logic_state
while True:
if relay_logic_state == 1:
relay.on()
#print("lamp on")
if relay_logic_state == 0:
relay.off()
#print("lamp off")
await asyncio.sleep_ms(500)
#================================== Стартиране на tasks...
async def main():
task1 = asyncio.create_task(read_DS3231())
task2 = asyncio.create_task(write_time_to_LCD())
task3 = asyncio.create_task(status_led_Core_1())
task4 = asyncio.create_task(button_read())
task5 = asyncio.create_task(relay_state())
task6 = asyncio.create_task(dht_read())
task6 = asyncio.create_task(write_temp_to_LCD())
task7 = asyncio.create_task(write_hum_to_LCD())
task8 = asyncio.create_task(PIR_control())
task9 = asyncio.create_task(write_control_to_LCD())
await asyncio.gather(task1, task2, task3, task4, task5, task6, task7, task8, task9)
asyncio.run(main())
1. Основен цикъл на Core 0
Основният цикъл на Core 0 започва с непрекъснато изпълнение на различни асинхронни функции, които се стартират в main()
.
2. status_led_Core_1
: Статус на Core 1
Тази асинхронна функция контролира статуса на LED индикатор, свързан към Core 1. LED-ът премигва на всеки 500ms, показвайки, че Core 1 работи нормално.
- Цикъл на мигане: LED-ът се включва и изключва с интервал от 500ms, използвайки
asyncio.sleep_ms()
, което позволява продължаване на изпълнението на други задачи.
3. dht_read
: Четене на DHT22 сензора
Тази функция периодично чете температурата и влажността от DHT22 сензора.
- Измерване и закръгляне на стойностите: След всяко измерване, стойностите на температурата и влажността се закръгляват до 1 десетична запетая и се съхраняват в глобалните променливи
temperature
иhumidity
. - Интервал на обновяване: Данните се обновяват на всеки 2 секунди.
4. read_DS3231
: Четене на DS3231 RTC
Функцията read_DS3231
чете текущата дата и час от RTC модула DS3231 и ги форматира като низове, които след това се показват на LCD дисплея.
- Изчитане и формат на данни: Датата и часът се извличат от модула и се форматират в две променливи
ds3231_year
иds3231_time
. - Интервал на обновяване: Данните се обновяват на всеки 10 секунди.
5. write_time_to_LCD
: Писане на време на LCD
Тази функция показва текущата дата и час на първия ред на LCD дисплея.
- Писане на LCD дисплея: Текущата дата и час се показват на първия ред, след което редът се изтрива след 30 секунди.
6. write_temp_to_LCD
и write_hum_to_LCD
: Писане на температура и влажност на LCD
Тези две функции отговарят за показването на температурата и влажността на съответните редове на LCD дисплея.
- Интервал на обновяване: Температурата се показва и изтрива след 40 секунди, а влажността — след 45 секунди.
7. write_control_to_LCD
: Писане на състоянието на лампата на LCD
Тази функция показва текущото състояние на лампата на втория ред на LCD дисплея.
- Контрол на дисплея: Състоянието на лампата (включена, изключена, или активиран PIR) се показва на LCD дисплея и се изтрива след 1.7 секунди.
8. button_read
: Четене на състоянието на бутона
Тази функция следи състоянието на бутона и реагира на всяко натискане, като променя състоянието на лампата и активира/деактивира PIR сензора.
- Превключване на състоянието на лампата: С натискане на бутона, лампата може да се включва, изключва, или да се активира PIR сензора.
- Деактивация на PIR сензора: PIR сензорът се деактивира, когато лампата се включи ръчно.
9. check_pir
и PIR_control
: Управление на PIR сензора
check_pir
: Тази функция просто връща текущото състояние на PIR сензора (дали е засечено движение).PIR_control
: Тази функция управлява лампата въз основа на сигнала от PIR сензора. Ако сензорът засече движение, лампата се включва за определен период от време, зададен вPIR_timer_stop
. Ако няма движение, лампата се изключва.
10. relay_state
: Управление на релето
Функцията relay_state
контролира състоянието на релето, което управлява лампата. В зависимост от състоянието на променливата relay_logic_state
, лампата се включва или изключва.
- Интервал на проверка: Състоянието на релето се проверява на всеки 500ms.
11. main
: Стартиране на всички задачи
В main()
се създават и стартират всички асинхронни задачи, използвайки asyncio.create_task()
. Задачите се изпълняват паралелно, благодарение на асинхронната природа на uasyncio
, което позволява на Core 0 да управлява множество задачи едновременно, без да блокира изпълнението им.
- Събиране на задачите: Всички задачи се събират и стартират едновременно с
asyncio.gather()
. - Изпълнение на задачите: Функцията
asyncio.run(main())
стартира основния цикъл на задачите.
Схема на ESP32 MicroPython управление на лампа с PIR и Wi-Fi Свързаност
В този параграф ще представя схемното решение на интелигентното устройство за управление на лампа с помощта на ESP32. Схемата включва свързването на различни хардуерни компоненти като PIR сензор, DHT22 сензор за температура и влажност, реле за управление на лампата, бутон за ръчно управление, и LCD дисплей с I2C интерфейс за визуализация на данните. ESP32 микроконтролерът е сърцето на устройството, осигурявайки както безжична свързаност чрез Wi-Fi, така и възможността за паралелно изпълнение на множество задачи. Всеки компонент е внимателно свързан към съответните GPIO пинове на ESP32, като са взети под внимание както захранващите изисквания, така и сигурността на електрическата схема. Тази схема е основата, върху която е изградена цялата система, осигурявайки надеждно и ефективно функциониране на устройството.
Захранваща част
Lamp-control-with-PIR-and-Web-interface-Power-SyplayРелейна част за включване на лампата
Lamp-control-with-PIR-and-Web-interface-Relay-PartПроцесор ESP32 и сензори LCD16x4, PIR, DHT, DS3231, Бутон
Lamp-control-with-PIR-and-Web-interface-PIR-DHT-RTCПлатка на проекта
![ESP32 MicroPython управление на лампа с PIR и Wi-Fi Свързаност PCB](http://ardudevelop.eu/wp-content/uploads/2024/08/ESP32-MicroPython-управление-на-лампа-с-PIR-и-Wi-Fi-Свързаност-PCB-718x1024.jpg)
WEB интерфейс
![ESP32 MicroPython управление на лампа с PIR и Wi-Fi Свързаност WEB интерфейс](http://ardudevelop.eu/wp-content/uploads/2024/08/ESP32-MicroPython-управление-на-лампа-с-PIR-и-Wi-Fi-Свързаност-WEB-интерфейс.png)
Видео демонстрация ESP32 MicroPython управление на лампа с PIR и Wi-Fi Свързаност
Заключение
Проектът демонстрира как ESP32 може да бъде използван за създаване на смарт устройство за управление на лампи в стая с помощта на MicroPython. Благодарение на използваните технологии като Wi-Fi, асинхронно програмиране и множество сензори, устройството предоставя удобно и ефективно управление на лампата, като същевременно показва полезна информация за околната среда на LCD дисплея.
Този проект може да бъде разширен и адаптиран за други приложения, като добавяне на допълнителни сензори, разширяване на уеб интерфейса и автоматизиране на повече аспекти от домашната среда.