[PORADNIK] Arduino IDE

krzychunh
Posts: 53
Joined: Mon Jul 12, 2021 6:23 am

Post

@Zibi_007 kosztował grosze 31,7zl na aliexpress. Pozostaje kalibracja. Mam oczyszczacz powietrza Samsung AX90R7080WD/EU ze wskazaniami PM10, PM2.5, PM1.0, będe starał się cokolwiek napisać po kalibracji wzorując na oczyszczaczu :)

Image
[email protected]
Posts: 1584
Joined: Mon Feb 06, 2023 8:56 am
Has thanked: 18 times
Been thanked: 26 times

Post

@krzychunh

co do PW:

Code: Select all

Cześć, czy mógłbyś sie podzielić konfiguracją wskazań pomiarów dla poszczególnych cząstek pyłów ?
Jaką konfiguracją? nie ma żadnej? Po prostu wyświetlałem sobie wartości, teraz akurat leży na biurku więc nic nie pokaże.
User avatar
Zibi_007
Posts: 3985
Joined: Tue Oct 31, 2023 10:06 pm
Has thanked: 10 times
Been thanked: 31 times

Post

krzychunh wrote: Sat Jan 24, 2026 4:20 pm @Zibi_007 kosztował grosze 31,7zl na aliexpress. Pozostaje kalibracja. Mam oczyszczacz powietrza Samsung AX90R7080WD/EU ze wskazaniami PM10, PM2.5, PM1.0, będe starał się cokolwiek napisać po kalibracji wzorując na oczyszczaczu :)

Image
W ten oczyszczacz to chyba jeszcze mniej wierzę ;-)
Ale obserwuj. Zobaczymy, jak to będzie wyglądać.

Zamówię sobie też. Mam możliwość sprawdzenia z czymś bardziej profesjonalnym.
Potestujemy... :)
Image Wiesz, że Supla obsługuje Zigbee? Wstąp do Klubu Promila: https://forum.supla.org/viewtopic.php?t=18018
Image Szukasz nowego GG? Jest tutaj: https://forum.supla.org/viewtopic.php?t=18036
krzychunh
Posts: 53
Joined: Mon Jul 12, 2021 6:23 am

Post

W Twoje możliwości bardziej wierzę niż w swoje odnośnie Supli ;), znalazłem na githubie, świeże wzmianki > https://github.com/paulvha/sps30/tree/master w dokumencie opisuje prace nad SPS30 tu-> https://github.com/paulvha/sps30/blob/master/sps30.odt
User avatar
Zibi_007
Posts: 3985
Joined: Tue Oct 31, 2023 10:06 pm
Has thanked: 10 times
Been thanked: 31 times

Post

krzychunh wrote: Sat Jan 24, 2026 10:07 pm W Twoje możliwości bardziej wierzę niż w swoje odnośnie Supli ;), znalazłem na githubie, świeże wzmianki > https://github.com/paulvha/sps30/tree/master w dokumencie opisuje prace nad SPS30 tu-> https://github.com/paulvha/sps30/blob/master/sps30.odt
Dzięki! No ciekawe.
Ja znalazłem kilka porównań.
Nieźle wygląda to:
Image

Przyjdzie, zmontuję, to sprawdzę ;-)
Image Wiesz, że Supla obsługuje Zigbee? Wstąp do Klubu Promila: https://forum.supla.org/viewtopic.php?t=18018
Image Szukasz nowego GG? Jest tutaj: https://forum.supla.org/viewtopic.php?t=18036
User avatar
SOYER
Posts: 1623
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry
Been thanked: 2 times

Post

Do poszukania dla wszystkich którzy wierzą w wysoką dokładność takich czujników, kalibrują je itd.
Poszeperajcie w hasłach:

zalecana wilgotność powietrza dla prawidłowych odczytów tego typu czujników laserowych

higroskopijność cząstek pyłu w warunkach wysokiej(?) wilgotności powyżej 70% a właściwie nawet 60% i tego implikacje

aktualną wilgotność powietrza w Polsce

średnia wilgotność powietrza w Polsce w warunkach zimowych

kondensacja pary w powietrzu i jej wpływ na odczyty czujników laserowych

sposób „mierzenia” przez te czujniki wszystkich zakresów średnic pyłu, mierzymy jeden, interpolujemy resztę

Stawiam banany przeciw orzechom, że po zgłębieniu tych tematów dacie sobie spokój z wiarą(tak to trzeba nazwać) w dokładność odczytu tych czujników w warunkach polskiej zimy. Jest to owszem jakiś wskaźnik, ostrzeżenie, ważna informacja, jednak realne poziomy mogą dalece odbiegać od realnych stanów zmierzonych w warunkach laboratoryjnych.
https://youtube.com/@tomaszhamer8134?si=_J1cT_QWsXxgt1Fm
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
https://github.com/Soyer79
krzychunh
Posts: 53
Joined: Mon Jul 12, 2021 6:23 am

Post

Podstawa przy podłączeniu to napięcie 5V i 2 rezystory 10K, SPS30 "GND z SEL, SCL, SDA i VCC" Połączenie zgodnie z poniższym schematem (gdzie dwa rezystory 10 kΩ są podłączone do okablowania SDA i SCL, a 5 V jako „rezystory podciągające”).
Obraz zapożyczony ze strony https://arbaair.org/2021/01/20/sensor-data-on-computer/
Image

Code: Select all

/*
  WebInterface + SPS30 I2C PM Sensory
  SUPLA Device with SPS30 Particulate Matter Sensor
  Copyright (C) AC SOFTWARE SP. Z O.O.
*/

#define STATUS_LED_GPIO 2
#define BUTTON_CFG_RELAY_GPIO 0

// ============================================
// SUPLA DEVICE INCLUDES
// ============================================
#include <SuplaDevice.h>
#include <supla/network/esp_wifi.h>
#include <supla/control/button.h>
#include <supla/device/status_led.h>
#include <supla/storage/littlefs_config.h>
#include <supla/network/esp_web_server.h>
#include <supla/network/html/device_info.h>
#include <supla/network/html/protocol_parameters.h>
#include <supla/network/html/status_led_parameters.h>
#include <supla/network/html/wifi_parameters.h>
#include <supla/events.h>

// ============================================
// PERSISTENT STORAGE
// ============================================
#include <supla/storage/eeprom.h>
Supla::Eeprom eeprom;

// ============================================
// SPS30 I2C SENSOR INCLUDES (sensirion-sps)
// ============================================
#include <Wire.h>
#include <math.h>
#include <sps30.h>                       // sensirion-sps
#include <sensirion_common.h>
#include <sensirion_i2c.h>

// ============================================
// SUPLA: kanały GPM
// ============================================
#include <supla/sensor/general_purpose_measurement.h>

// ============================================
// GLOBAL OBJECTS
// ============================================
Supla::ESPWifi wifi;
Supla::LittleFsConfig configSupla;
Supla::Device::StatusLed statusLed(STATUS_LED_GPIO, true);
Supla::EspWebServer suplaServer;

// ============================================
// SUPLA AUTHKEY
// ============================================
// Generate from: https://www.supla.org/arduino/get-authkey
char AUTHKEY[SUPLA_AUTHKEY_SIZE] = {
  0xE2, 0x5C, 0xD7, 0x8D, 0xF1, 0xD1, 0xA7, 0x38,
  0xE1, 0xB9, 0xAF, 0xB6, 0xC1, 0x5A, 0x30, 0xEF
};

// ============================================
// SPS30: kanały MASOWE (µg/m³) – “czytelne”
/*
  m.mc_1p0  -> PM1.0  (µg/m³)
  m.mc_2p5  -> PM2.5  (µg/m³)
  m.mc_4p0  -> PM4.0  (µg/m³)
  m.mc_10p0 -> PM10   (µg/m³)
*/
// ============================================
static Supla::Sensor::GeneralPurposeMeasurement *chPM1   = nullptr;
static Supla::Sensor::GeneralPurposeMeasurement *chPM25  = nullptr;
static Supla::Sensor::GeneralPurposeMeasurement *chPM4   = nullptr;
static Supla::Sensor::GeneralPurposeMeasurement *chPM10  = nullptr;

static bool spsReady = false;
static unsigned long lastSpsReadMs = 0;

// Prosta ochrona przed NaN/INF i “śmieciami”
static float saneF(float v) {
  if (isnan(v) || isinf(v)) return NAN;
  if (v < 0) return 0;
  if (v > 5000.0f) return NAN; // PM w µg/m³ powyżej kilku tys. to zwykle błąd / zła ramka
  return v;
}

static void sps30Init() {
  Serial.println();
  Serial.println("🔥 Initializing SPS30 (sensirion-sps) ...");

  // I2C na ESP32 – SDA=21, SCL=22 (bez zmiany Twoich połączeń)
  Wire.begin(21, 22);
  Wire.setClock(100000);

  sensirion_i2c_init();
  delay(200);

  int16_t ret = sps30_probe();
  if (ret) {
    Serial.print("❌ SPS30 probe failed, ret="); Serial.println(ret);
    spsReady = false;
    return;
  }
  Serial.println("✅ SPS30 found (probe OK)");

  // Start pomiaru
  ret = sps30_start_measurement();
  if (ret) {
    Serial.print("❌ sps30_start_measurement failed, ret="); Serial.println(ret);
    spsReady = false;
    return;
  }

  Serial.println("✅ SPS30 measurements started");
  spsReady = true;
}

static void sps30ReadAndPublish() {
  if (!spsReady) return;

  // odczyt co 5s
  const unsigned long intervalMs = 5000;
  if (millis() - lastSpsReadMs < intervalMs) return;
  lastSpsReadMs = millis();

  // Najpierw sprawdź czy dane gotowe (żeby nie dostawać “data not ready”)
  uint16_t ready = 0;
  int16_t ret = sps30_read_data_ready(&ready);
  if (ret) {
    static uint8_t errCnt = 0;
    if ((errCnt++ % 10) == 0) {
      Serial.print("⚠️ sps30_read_data_ready ret="); Serial.println(ret);
    }
    return;
  }
  if (!ready) {
    return; // dane jeszcze niegotowe
  }

  struct sps30_measurement m;
  ret = sps30_read_measurement(&m);
  if (ret) {
    static uint8_t errCnt2 = 0;
    if ((errCnt2++ % 10) == 0) {
      Serial.print("⚠️ SPS30 read ret="); Serial.println(ret);
    }
    return;
  }

  // MASA (µg/m³) – to jest to, czego chcesz dla “zwykłego użytkownika”
  float pm1  = saneF(m.mc_1p0);
  float pm25 = saneF(m.mc_2p5);
  float pm4  = saneF(m.mc_4p0);
  float pm10 = saneF(m.mc_10p0);

  if (chPM1)  chPM1->setValue(pm1);
  if (chPM25) chPM25->setValue(pm25);
  if (chPM4)  chPM4->setValue(pm4);
  if (chPM10) chPM10->setValue(pm10);

  Serial.print("SPS30 mass [ug/m3]: ");
  Serial.print("PM1=");  Serial.print(pm1);
  Serial.print(" PM2.5="); Serial.print(pm25);
  Serial.print(" PM4="); Serial.print(pm4);
  Serial.print(" PM10="); Serial.println(pm10);
}

// ============================================
// SETUP
// ============================================
void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println();
  Serial.println("========================================");
  Serial.println("🚀 SUPLA WebInterface + SPS30 I2C PM");
  Serial.println("========================================");

  // HTML configuration pages (accessible at 192.168.4.1)
  Serial.println("📱 Creating web config pages...");
  new Supla::Html::DeviceInfo(&SuplaDevice);
  new Supla::Html::WifiParameters;
  new Supla::Html::ProtocolParameters;
  new Supla::Html::StatusLedParameters;

  // Configuration button (GPIO0 = BOOT pin)
  Serial.println("🔘 Setting up config button (GPIO0)...");
  new Supla::Control::Button(BUTTON_CFG_RELAY_GPIO, true, true);

  // ============================================
  // ADD SPS30 PM MASS CHANNELS TO SUPLA (GPM)
  // ============================================
  Serial.println();
  Serial.println("📊 Adding PM mass channels to SUPLA...");

  chPM1  = new Supla::Sensor::GeneralPurposeMeasurement();
  chPM25 = new Supla::Sensor::GeneralPurposeMeasurement();
  chPM4  = new Supla::Sensor::GeneralPurposeMeasurement();
  chPM10 = new Supla::Sensor::GeneralPurposeMeasurement();

  chPM1 ->setInitialCaption("PM1.0");
  chPM25->setInitialCaption("PM2.5");
  chPM4 ->setInitialCaption("PM4.0");
  chPM10->setInitialCaption("PM10");

  // Jednostki “czytelne”
  chPM1 ->setDefaultUnitAfterValue("ug/m3");
  chPM25->setDefaultUnitAfterValue("ug/m3");
  chPM4 ->setDefaultUnitAfterValue("ug/m3");
  chPM10->setDefaultUnitAfterValue("ug/m3");

  Serial.println("   ✅ PM channels added (4x GPM, mass)!");

  // ============================================
  // SPS30 init
  // ============================================
  sps30Init();

  // ============================================
  // (Opcjonalnie) I2C Scanner
  // ============================================
  Serial.println("🔍 I2C Scanner...");
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print("I2C device found: 0x"); Serial.println(addr, HEX);
    }
  }
  Serial.println("I2C scan END");
  delay(500);

  // ============================================
  // SUPLA DEVICE CONFIGURATION
  // ============================================
  Serial.println("⚙️  Configuring SUPLA Device...");

  SuplaDevice.setInitialMode(Supla::InitialMode::StartInCfgMode);
  SuplaDevice.begin();

  Serial.println("✅ SUPLA Device started!");

  Serial.println();
  Serial.println("========================================");
  Serial.println("🌐 SUPLA Configuration AP Ready!");
  Serial.println("   SSID: supla-XXXX (find in WiFi list)");
  Serial.println("   Password: supla123");
  Serial.println("   Web: 192.168.4.1");
  Serial.println();
  Serial.println("📱 Channels:");
  Serial.println("   Ch0: PM1.0  (ug/m3)");
  Serial.println("   Ch1: PM2.5  (ug/m3) ⭐");
  Serial.println("   Ch2: PM4.0  (ug/m3)");
  Serial.println("   Ch3: PM10   (ug/m3)");
  Serial.println("========================================");
  Serial.println();
  Serial.println("⏳ SPS30: pierwsze sensowne dane zwykle po kilku–kilkunastu sekundach od start_measurement()");
}

// ============================================
// MAIN LOOP
// ============================================
void loop() {
  SuplaDevice.iterate();
  sps30ReadAndPublish();
}

Return to “FAQ / Jak to zrobić”