🔌

Projekty Arduino i Elektronika

Kompletne projekty z kodem, schematem połączeń i listą komponentów. Każdy projekt testowany w praktyce, każdy ma zdjęcia i wyjaśnienie działania.

Arduino 12 maja 2026 ⏱ 18 min czytania

Stacja pogodowa Arduino z OLED, WiFi i powiadomieniami na Telegram

Koszt budowy: ok. 75–90 zł | Poziom: Średniozaawansowany | Czas montażu: 3–4 godziny

Opis projektu

Stacja pogodowa to jeden z najlepszych projektów startowych – jest wystarczająco prosta, by skończyć ją w weekend, ale na tyle rozbudowana, że naprawdę uczysz się obsługi czujników, komunikacji I2C, WiFi oraz API zewnętrznych usług. Nasz projekt mierzy temperaturę, wilgotność powietrza i ciśnienie atmosferyczne, a wyniki wyświetla na wyświetlaczu OLED i wysyła co godzinę raport na Telegrama.

💡 Po co Telegram? Możesz ustawić alerty – np. gdy temperatura spada poniżej 0°C lub wilgotność przekracza 85% (ryzyko pleśni). Bot Telegram działa przez HTTPS i nie wymaga żadnych serwerów po Twojej stronie.

Lista komponentów

KomponentModelCena (przybliżona)
Mikrokontroler z WiFiESP32 DevKit v1 lub NodeMCU ESP826618–28 zł
Czujnik temp. + wilgotnościDHT22 (dokładniejszy niż DHT11)8–12 zł
Czujnik ciśnieniaBMP280 (I2C)6–10 zł
Wyświetlacz OLED0.96" SSD1306 128x64 (I2C)8–14 zł
Rezystor 10kΩDo linii danych DHT22<1 zł
Płytka stykowa + kable400-otworowa + kable DuPont10–15 zł
Zasilacz 5V micro-USBStandard 1A+10–15 zł

Schemat połączeń

Połączenia dla ESP32 (piny mogą się różnić dla ESP8266 – sprawdź pinout swojej płytki):

DHT22:
  VCC  → 3.3V
  GND  → GND
  DATA → GPIO4 (z rezystorem 10kΩ do 3.3V)

BMP280 (I2C):
  VCC → 3.3V
  GND → GND
  SDA → GPIO21
  SCL → GPIO22

OLED SSD1306 (I2C, współdzieli szyne z BMP280):
  VCC → 3.3V
  GND → GND
  SDA → GPIO21
  SCL → GPIO22
  (adres domyślny: 0x3C, BMP280: 0x76)

Kompletny kod

Zainstaluj wymagane biblioteki przez Arduino Library Manager: DHT sensor library, Adafruit BMP280, Adafruit SSD1306, UniversalTelegramBot, ArduinoJson.

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <DHT.h>
#include <Adafruit_BMP280.h>
#include <Adafruit_SSD1306.h>
#include <UniversalTelegramBot.h>

// --- Konfiguracja ---
const char* SSID       = "TwojeSIECI_WIFI";
const char* PASS       = "TwojeHaslo";
const char* BOT_TOKEN  = "TWOJ_TOKEN_TELEGRAM";
const String CHAT_ID   = "TWOJE_CHAT_ID";

#define DHTPIN  4
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP280 bmp;
Adafruit_SSD1306 display(128, 64, &Wire, -1);
WiFiClientSecure client;
UniversalTelegramBot bot(BOT_TOKEN, client);

unsigned long lastReport = 0;
const unsigned long REPORT_INTERVAL = 3600000UL; // 1 godzina

void setup() {
  Serial.begin(115200);
  dht.begin();

  // OLED init
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("OLED nie znaleziony!");
    while(true);
  }
  display.clearDisplay();
  display.setTextColor(WHITE);

  // BMP280 init
  if (!bmp.begin(0x76)) {
    Serial.println("BMP280 nie znaleziony!");
    while(true);
  }

  // WiFi
  WiFi.begin(SSID, PASS);
  display.setCursor(0, 0);
  display.print("Laczenie z WiFi...");
  display.display();
  while (WiFi.status() != WL_CONNECTED) {
    delay(500); Serial.print(".");
  }
  client.setInsecure(); // tylko do testów; w produkcji użyj certyfikatu

  Serial.println("\nPolaczono: " + WiFi.localIP().toString());
}

void sendTelegramReport(float temp, float hum, float pres) {
  String msg = "🌡 *Raport stacji pogodowej*\n";
  msg += "Temperatura: *" + String(temp, 1) + " °C*\n";
  msg += "Wilgotność: *" + String(hum, 1) + " %*\n";
  msg += "Ciśnienie: *" + String(pres/100.0, 1) + " hPa*\n";
  if (temp < 0)   msg += "⚠️ _Uwaga: przymrozki!_\n";
  if (hum > 85)   msg += "⚠️ _Wysoka wilgotność – ryzyko pleśni_\n";
  bot.sendMessage(CHAT_ID, msg, "Markdown");
}

void updateDisplay(float temp, float hum, float pres) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("iPraktyk.pl Stacja");
  display.drawLine(0, 9, 128, 9, WHITE);

  display.setTextSize(2);
  display.setCursor(0, 14);
  display.print(temp, 1); display.println(" C");

  display.setTextSize(1);
  display.setCursor(0, 36);
  display.print("Wilg: "); display.print(hum, 1); display.println(" %");
  display.print("Cis:  "); display.print(pres/100.0, 1); display.println(" hPa");
  display.display();
}

void loop() {
  float temp = dht.readTemperature();
  float hum  = dht.readHumidity();
  float pres = bmp.readPressure();

  if (!isnan(temp) && !isnan(hum)) {
    updateDisplay(temp, hum, pres);
    if (millis() - lastReport >= REPORT_INTERVAL || lastReport == 0) {
      sendTelegramReport(temp, hum, pres);
      lastReport = millis();
    }
  }
  delay(5000);
}

Konfiguracja bota Telegram

1

Utwórz bota przez BotFather

Otwórz Telegram, wyszukaj @BotFather, wyślij /newbot i postępuj z instrukcjami. Otrzymasz token API – skopiuj go do zmiennej BOT_TOKEN.

2

Pobierz swoje Chat ID

Wyślij wiadomość do bota, a następnie wejdź w przeglądarce na: https://api.telegram.org/bot<TOKEN>/getUpdates. W odpowiedzi JSON znajdziesz pole chat.id.

3

Wgraj kod na ESP32

Uzupełnij dane WiFi, token i Chat ID, a następnie wgraj kod. Monitor szeregowy pokaże IP urządzenia i status połączenia.

⚠️ Bezpieczeństwo: Nigdy nie umieszczaj tokenów i haseł bezpośrednio w kodzie, jeśli udostępniasz go publicznie (np. na GitHub). Użyj pliku konfiguracyjnego lub zmiennych środowiskowych.
Arduino 8 maja 2026 ⏱ 12 min czytania

Domowy alarm z czujnikiem PIR za 50 zł

Koszt: ok. 45–55 zł | Poziom: Początkujący | Czas: 1–2 godziny

Czujnik PIR (Passive Infrared) wykrywa zmiany w promieniowaniu podczerwonym – czyli ruch ciepłych obiektów, takich jak ludzie lub zwierzęta. To jeden z najtańszych i najłatwiejszych sposobów na budowę prostego systemu detekcji ruchu. Rozbudujemy go o buzzer alarmowy i opcjonalne powiadomienie przez WiFi.

Potrzebne komponenty

KomponentCena
Arduino Uno R3 lub klon22–35 zł
Czujnik PIR HC-SR5015–8 zł
Buzzer aktywny 5V2–4 zł
Dioda LED czerwona + rezystor 220Ω1 zł
Płytka stykowa + kable10–15 zł

Kalibracja czujnika PIR

Moduł HC-SR501 ma dwa potencjometry na spodzie płytki:

  • Sensitivity (Sx): Reguluje czułość (zasięg wykrywania 3–7 m). Obróć do końca zgodnie z ruchem wskazówek zegara dla maksymalnego zasięgu.
  • Time delay (Tx): Czas aktywacji wyjścia po wykryciu ruchu (3 s – 5 min). Na początku ustaw na minimum.

Tryb pracy wybierasz zworką: L (Retriggering) – sygnał utrzymuje się przez czas Tx od ostatniego wykrycia ruchu (zalecany dla alarmu).

const int PIR_PIN   = 7;
const int LED_PIN   = 13;
const int BUZZ_PIN  = 8;
const int ALARM_DUR = 3000; // czas alarmu w ms

void setup() {
  pinMode(PIR_PIN,  INPUT);
  pinMode(LED_PIN,  OUTPUT);
  pinMode(BUZZ_PIN, OUTPUT);
  Serial.begin(9600);
  // Poczekaj na kalibrację czujnika (30–60 s)
  Serial.println("Kalibracja PIR...");
  delay(60000);
  Serial.println("Gotowy!");
}

void loop() {
  if (digitalRead(PIR_PIN) == HIGH) {
    Serial.println("RUCH WYKRYTY!");
    digitalWrite(LED_PIN, HIGH);
    // Alarm pulsujący
    for (int i = 0; i < 6; i++) {
      digitalWrite(BUZZ_PIN, HIGH); delay(200);
      digitalWrite(BUZZ_PIN, LOW);  delay(100);
    }
    delay(ALARM_DUR);
    digitalWrite(LED_PIN, LOW);
  }
  delay(100);
}
🚀 Rozbudowa projektu: Dodaj moduł ESP8266 (lub zastąp Arduino Uno płytką ESP32) i wysyłaj powiadomienie push przez IFTTT lub bot Telegram gdy czujnik wykryje ruch. Połącz kilka czujników PIR na różnych pinach i zrób strefowy system alarmowy.
Arduino 2 maja 2026 ⏱ 20 min czytania

Automatyczny sterownik nawadniania ogrodu z panelem webowym

Koszt: ok. 90–130 zł | Poziom: Średniozaawansowany | Czas: pół dnia

Koniec z zapominaniem o podlewaniu ogrodu. Ten projekt pozwala ustawić harmonogram nawadniania i sterować zaworami przez przeglądarkę z dowolnego urządzenia w sieci domowej. Używamy ESP32 jako serwera HTTP, przekaźnika do sterowania zaworem solenoidowym i opcjonalnie czujnika wilgotności gleby, który wyłącza podlewanie gdy gleba jest mokra.

Architektura systemu

📡
Komunikacja
WiFi + HTTP
💧
Sterowanie
Przekaźnik 5V
🌱
Sensor
Czujnik gleby
Harmonogram
RTC DS3231
🖥
Panel
Web UI
🔋
Zasilanie
5V USB-C

Kluczowy fragment kodu – serwer HTTP

#include <WiFi.h>
#include <WebServer.h>
#include <RTClib.h>

WebServer server(80);
RTC_DS3231 rtc;

const int RELAY_PIN    = 26;
const int SOIL_PIN     = 34; // ADC
bool      wateringOn   = false;
int       startHour    = 6;
int       durationMin  = 20;

// HTML panelu sterowania (minified)
const char* INDEX_HTML = R"rawliteral(
<!DOCTYPE html><html lang='pl'><head>
<meta charset='UTF-8'><meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Nawadnianie</title>
<style>body{font-family:sans-serif;max-width:400px;margin:2rem auto;background:#111;color:#eee;padding:1rem}
button{padding:.8rem 1.5rem;border:none;border-radius:8px;cursor:pointer;font-size:1rem;margin:.3rem}
.on{background:#22c55e;color:#000}.off{background:#ef4444;color:#fff}
.card{background:#1a2030;border:1px solid #334;border-radius:10px;padding:1rem;margin:.8rem 0}
input[type=number]{background:#222;color:#fff;border:1px solid #444;border-radius:6px;padding:.4rem;width:60px}</style>
</head><body>
<h2>🌱 Sterownik nawadniania</h2>
<div class='card' id='status'>Ładowanie...</div>
<div class='card'>
  <p>Godzina startu: <input type='number' id='sh' min='0' max='23' value='6'> : 00</p>
  <p>Czas trwania: <input type='number' id='dur' min='1' max='120' value='20'> minut</p>
  <button class='on' onclick='setSchedule()'>Ustaw harmonogram</button>
</div>
<div class='card'>
  <button class='on' onclick='ctrl(1)'>💧 Włącz teraz</button>
  <button class='off' onclick='ctrl(0)'>⏹ Wyłącz</button>
</div>
<script>
function ctrl(s){fetch('/control?state='+s).then(r=>r.text()).then(t=>document.getElementById('status').innerText=t)}
function setSchedule(){fetch('/schedule?hour='+document.getElementById('sh').value+'&dur='+document.getElementById('dur').value)}
setInterval(()=>fetch('/status').then(r=>r.json()).then(d=>{
  document.getElementById('status').innerHTML=
    '💧 Zawór: '+(d.valve?'<b style=color:#22c55e>OTWARTY</b>':'ZAMKNIĘTY')+
    '<br>🌡 Wilgotność gleby: '+d.soil+'%'+
    '<br>⏰ Czas: '+d.time
}),3000);
</script></body></html>)rawliteral";

String getSoilPercent() {
  int raw = analogRead(SOIL_PIN);
  int pct = map(raw, 4095, 1500, 0, 100);
  return String(constrain(pct, 0, 100));
}

void handleRoot()     { server.send(200, "text/html", INDEX_HTML); }
void handleControl()  {
  bool s = server.arg("state") == "1";
  digitalWrite(RELAY_PIN, s ? LOW : HIGH);
  wateringOn = s;
  server.send(200, "text/plain", s ? "Nawadnianie włączone" : "Nawadnianie wyłączone");
}
void handleStatus() {
  DateTime now = rtc.now();
  char timebuf[9]; sprintf(timebuf, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
  String json = "{\"valve\":" + String(wateringOn ? "true" : "false") +
                ",\"soil\":" + getSoilPercent() +
                ",\"time\":\"" + timebuf + "\"}";
  server.send(200, "application/json", json);
}

void setup() {
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, HIGH); // przekaźnik NC – wysoki = otwarty obwód
  rtc.begin();
  WiFi.begin("TwojeSSID", "TwojeHaslo");
  while (WiFi.status() != WL_CONNECTED) delay(500);
  Serial.println("IP: " + WiFi.localIP().toString());
  server.on("/", handleRoot);
  server.on("/control", handleControl);
  server.on("/status", handleStatus);
  server.begin();
}

void loop() {
  server.handleClient();
  // Sprawdź harmonogram
  DateTime now = rtc.now();
  if (now.hour() == startHour && now.minute() == 0 && now.second() < 10) {
    int soil = analogRead(SOIL_PIN);
    if (soil > 2500) { // gleba sucha
      digitalWrite(RELAY_PIN, LOW);
      wateringOn = true;
      delay((long)durationMin * 60000L);
      digitalWrite(RELAY_PIN, HIGH);
      wateringOn = false;
    }
  }
}
Narzędzia 25 kwietnia 2026 ⏱ 10 min czytania

Arduino w VS Code – porzuć stare IDE raz na zawsze

Oficjalne Arduino IDE 2.x jest znacznie lepsze niż jego poprzednik, ale VS Code z Arduino CLI oferuje to, czego żadne dedykowane IDE nie da: pełne podpowiedzi IntelliSense, świetne zarządzanie plikami projektu, integrację z Git, terminal wbudowany i możliwość pracy z dowolnym zestawem narzędzi. Jeśli programujesz już w VS Code w innych językach – zostań tam na zawsze.

Instalacja krok po kroku

1

Zainstaluj Arduino CLI

Pobierz plik binarny ze strony arduino.github.io/arduino-cli lub przez menedżer pakietów:

# Linux / macOS
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh

# Windows (PowerShell)
winget install Arduino.ArduinoCLI
2

Zainstaluj rozszerzenie Arduino w VS Code

W VS Code otwórz Extensions (Ctrl+Shift+X) i wyszukaj Arduino od Microsoft. Po zainstalowaniu wejdź w ustawienia rozszerzenia i ustaw ścieżkę do arduino-cli.

3

Skonfiguruj profil tablicy

# Dodaj rdzeń dla Arduino AVR (Uno, Nano, Mega)
arduino-cli core install arduino:avr

# Dla ESP8266
arduino-cli config add board_manager.urls \
  https://arduino.esp8266.com/stable/package_esp8266com_index.json
arduino-cli core install esp8266:esp8266

# Dla ESP32
arduino-cli config add board_manager.urls \
  https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
arduino-cli core install esp32:esp32
4

Skompiluj i wgraj przez CLI

# Kompilacja (fqbn = fully qualified board name)
arduino-cli compile --fqbn arduino:avr:uno MojProjekt/

# Wykryj port COM/ttyUSB
arduino-cli board list

# Wgraj firmware
arduino-cli upload -p /dev/ttyUSB0 --fqbn arduino:avr:uno MojProjekt/

# Monitor szeregowy
arduino-cli monitor -p /dev/ttyUSB0 --config baudrate=9600
💡 Tip pro: Dodaj plik .clangd do projektu z flagami kompilatora AVR, a IntelliSense przestanie pokazywać fałszywe błędy dla typów specyficznych dla Arduino (byte, String, Serial).