import network
import urequests
import ntptime
import time
from machine import Pin, ADC, I2C
from dht import DHT22
# --- Настройки пинов ---
DHT_PIN = 4
MQ2_PIN = 34
RED_PIN = 26
GREEN_PIN = 25
BLUE_PIN = 33
BUTTON_SEND_PIN = 2
BUTTON_MODE_PIN = 16
I2C_SCL_PIN = 22
I2C_SDA_PIN = 21
# --- Wi-Fi ---
SSID = "Wokwi-GUEST"
PASSWORD = ""
# --- Google Apps Script URL ---
GOOGLE_APPS_SCRIPT_URL = "https://script.google.com/macros/s/AKfycbw5PgFCRykNA1gCEMaEediQzSdvHCtr37_BBSyvL1P9Zdq5ADWbZ2iC47s3qHK7ICCZdA/exec"
# --- Глобальные переменные ---
display_mode = False # False - датчики, True - прогноз
last_button_send_press = 0
last_button_mode_press = 0
button_debounce_ms = 300
# Фейковые данные прогноза
fake_temp = 15.5
fake_desc = "Clear"
# --- Инициализация ---
wifi = network.WLAN(network.STA_IF)
dht_sensor = DHT22(Pin(DHT_PIN))
mq2_sensor = ADC(Pin(MQ2_PIN))
mq2_sensor.atten(ADC.ATTN_11DB)
red_led = Pin(RED_PIN, Pin.OUT)
green_led = Pin(GREEN_PIN, Pin.OUT)
blue_led = Pin(BLUE_PIN, Pin.OUT)
button_send = Pin(BUTTON_SEND_PIN, Pin.IN, Pin.PULL_UP)
button_mode = Pin(BUTTON_MODE_PIN, Pin.IN, Pin.PULL_UP)
i2c = I2C(0, scl=Pin(I2C_SCL_PIN), sda=Pin(I2C_SDA_PIN), freq=400000)
class SimpleLCD:
def __init__(self, i2c, addr=0x27, rows=4, cols=20):
self.i2c = i2c
self.addr = addr
self.rows = rows
self.cols = cols
self.backlight = 0x08
time.sleep(0.05)
self.init_lcd()
def init_lcd(self):
self._cmd(0x33)
self._cmd(0x32)
self._cmd(0x28)
self._cmd(0x0C)
self._cmd(0x06)
self.clear()
def _cmd(self, cmd):
self._send(cmd, 0)
def _write(self, data):
self._send(data, 1)
def _send(self, value, mode):
high = value & 0xF0
low = (value << 4) & 0xF0
self._write_byte(high | mode | self.backlight)
self._pulse(high | mode | self.backlight)
self._write_byte(low | mode | self.backlight)
self._pulse(low | mode | self.backlight)
def _write_byte(self, data):
self.i2c.writeto(self.addr, bytes([data]))
def _pulse(self, data):
self._write_byte(data | 0x04)
time.sleep_us(100)
self._write_byte(data & ~0x04)
time.sleep_us(100)
def clear(self):
self._cmd(0x01)
time.sleep_ms(2)
def set_cursor(self, row, col):
offsets = [0x00, 0x40, 0x14, 0x54]
if row >= self.rows:
row = self.rows - 1
self._cmd(0x80 | (offsets[row] + col))
def putstr(self, string):
for ch in string:
self._write(ord(ch))
def connect_wifi():
print("Connecting to Wi-Fi...")
wifi.active(True)
wifi.connect(SSID, PASSWORD)
for _ in range(15):
if wifi.isconnected():
print("Connected:", wifi.ifconfig())
try:
ntptime.host = 'pool.ntp.org'
ntptime.settime()
print("Time synchronized")
except:
print("NTP sync failed")
return True
time.sleep(1)
print("Wi-Fi connection failed")
return False
def get_time_str():
tm = time.localtime()
return "{:02d}:{:02d}".format(tm[3], tm[4]), tm
def get_day_str(weekday):
days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
return days[weekday] if 0 <= weekday < 7 else "N/A"
def get_month_str(month):
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
return months[month - 1] if 1 <= month <= 12 else "N/A"
def read_sensors():
try:
dht_sensor.measure()
temp = dht_sensor.temperature()
hum = dht_sensor.humidity()
except:
temp, hum = None, None
try:
air_quality = mq2_sensor.read()
except:
air_quality = None
return temp, hum, air_quality
def set_rgb(r, g, b):
red_led.value(1 if r else 0)
green_led.value(1 if g else 0)
blue_led.value(1 if b else 0)
def interpret_air_quality(value):
if value is None:
return "N/A"
if value > 2000:
return "Bad"
elif value >= 1700:
return "Mid"
else:
return "Good"
def send_data(temp, hum, air_quality):
if not wifi.isconnected():
print("Wi-Fi not connected, can't send data.")
return
timestamp, _ = get_time_str()
try:
data = {
"method": "append",
"temperature": temp if temp is not None else "N/A",
"humidity": hum if hum is not None else "N/A",
"airQuality": air_quality if air_quality is not None else "N/A",
"timestamp": timestamp,
"buttonState": str(button_mode.value() == 0).lower()
}
print("Sending data:", data)
response = urequests.post(GOOGLE_APPS_SCRIPT_URL, json=data)
print("Response:", response.status_code, response.text)
response.close()
except Exception as e:
print("Failed to send data:", e)
def draw_datetime(lcd, tm):
"""Отрисовка даты и времени внизу справа (строка 3, колонка 14) и даты в строке 2 справа."""
current_time_str = "{:02d}:{:02d}".format(tm[3], tm[4])
day_str = get_day_str(tm[6])
month_str = get_month_str(tm[1])
date_str = "{},{:02d} {}".format(day_str, tm[2], month_str)
# Отрисовка даты в строке 2 справа
col_for_date = max(0, 20 - len(date_str))
lcd.set_cursor(2, col_for_date)
lcd.putstr(date_str + " ") # добавляем пробелы для очистки
# Отрисовка времени в строке 3 справа
lcd.set_cursor(3, 14)
lcd.putstr(current_time_str)
lcd = SimpleLCD(i2c)
lcd.clear()
lcd.putstr("Weather Station")
time.sleep(1)
lcd.clear()
if not connect_wifi():
lcd.putstr("Wi-Fi failed!")
else:
lcd.putstr("Wi-Fi OK")
time.sleep(1)
lcd.clear()
last_minute = -1
last_temp = None
last_hum = None
last_air = None
last_update_values = 0
forecast_drawn = False
while True:
now_ms = time.ticks_ms()
tm = time.localtime()
# Кнопка отправки данных
if button_send.value() == 0 and time.ticks_diff(now_ms, last_button_send_press) > button_debounce_ms:
print("Send button pressed")
temp, hum, air_quality = read_sensors()
send_data(temp, hum, air_quality)
last_button_send_press = now_ms
# Кнопка смены режима отображения
if button_mode.value() == 0 and time.ticks_diff(now_ms, last_button_mode_press) > button_debounce_ms:
display_mode = not display_mode
lcd.clear()
last_temp = None
last_hum = None
last_air = None
last_update_values = 0
forecast_drawn = False
last_button_mode_press = now_ms
print("Display mode switched to", "Forecast" if display_mode else "Sensors")
# Рисуем дату и время сразу после очистки
draw_datetime(lcd, tm)
# Обновление времени и даты при изменении минуты
if tm[4] != last_minute:
last_minute = tm[4]
draw_datetime(lcd, tm)
# Режим сенсоров
if not display_mode and time.ticks_diff(now_ms, last_update_values) > 2000:
temp, hum, air_quality = read_sensors()
if temp is not None:
last_temp = temp
if hum is not None:
last_hum = hum
if air_quality is not None:
last_air = air_quality
# Строка 0: Температура
lcd.set_cursor(0, 0)
if last_temp is not None:
lcd.putstr("Temp:{:5.1f} C".format(last_temp))
else:
lcd.putstr("Temp:N/A")
# Строка 1: Влажность
lcd.set_cursor(1, 0)
if last_hum is not None:
lcd.putstr("Hum:{:5.1f}%".format(last_hum))
else:
lcd.putstr("Hum:N/A")
# Строка 2: Качество воздуха
lcd.set_cursor(2, 0)
air_quality_str = interpret_air_quality(last_air)
lcd.putstr("Air:{:>4} ".format(air_quality_str))
# RGB LED цвет по качеству воздуха
if air_quality_str == "Good":
set_rgb(0, 1, 0)
elif air_quality_str == "Mid":
set_rgb(1, 1, 0)
elif air_quality_str == "Bad":
set_rgb(1, 0, 0)
else:
set_rgb(0, 0, 0)
last_update_values = now_ms
# Режим прогноза
if display_mode and not forecast_drawn:
lcd.clear()
# Заголовок
lcd.putstr("Forecast:")
lcd.set_cursor(1, 0)
lcd.putstr("Temp:{:5.1f} C".format(fake_temp))
lcd.set_cursor(2, 0)
lcd.putstr("Desc:{:<15}".format(fake_desc))
forecast_drawn = True
time.sleep(0.1)