DIY Stacja pogodowa Z ESP32 — Esp32 C6 simulation

An interactive Esp32 C6 circuit simulation you can run free in your browser on Velxio, by kshyhoo.

Components

Sketch code

#include <WiFi.h>
#include <Wire.h>
#include <math.h>  // fabs()
#include <HTTPClient.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

const char* ssid = "Velxio-GUEST";
const char* pass = "";
const int wifiChannel = 6;  // wymuszony kanał – pomija skanowanie sieci

const char* serverURL = "http://kshyhoo.eu/weather/wind.php";
// Prosty „sekret” chroniący endpoint przed przypadkowym albo złośliwym
// nadpisaniem danych przez kogoś innego, kto zgadnie adres URL. Musi być
// identyczny z wartością sprawdzaną w wind.php
const char* apiToken = "kshyhoo";

unsigned long lastSend = 0;
const unsigned long sendInterval = 5000;  // co ile ms wysyłać dane
// KIERUNEK WIATRU (AS5600)
#define SDA_PIN 23
#define SCL_PIN 22

#define WIND_I2C_ADDR 0x36
#define WIND_REG_RAW_ANGLE_HI 0x0C

uint16_t readAs5600RawAngle() {
  Wire.beginTransmission(WIND_I2C_ADDR);
  Wire.write(WIND_REG_RAW_ANGLE_HI);
  if (Wire.endTransmission(false) != 0) {
    Serial.println("AS5600: błąd I2C przy ustawianiu wskaźnika rejestru!");
    return 0xFFFF;
  }
  Wire.requestFrom((int)WIND_I2C_ADDR, 2);
  if (Wire.available() < 2) {
    Serial.println("AS5600: za mało bajtów w odpowiedzi I2C!");
    return 0xFFFF;
  }
  uint8_t hi = Wire.read();
  uint8_t lo = Wire.read();
  return ((uint16_t)(hi & 0x0F) << 8) | lo;
}

const char* angleToCompass(float degrees) {
  static const char* names[] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW" };
  int sector = (int)((degrees + 22.5) / 45.0) % 8;
  if (sector < 0) sector += 8;
  return names[sector];
}

float lastAngleDeg = -1;

void updateWindDirection() {
  uint16_t raw = readAs5600RawAngle();
  if (raw == 0xFFFF) {
    return;
  }
  lastAngleDeg = raw * 360.0 / 4096.0;
}
// PRĘDKOŚĆ WIATRU (ANEMOMETR - A3144)
// Wyjście OUT anemometru to open-collector (jak A3144) - INPUT_PULLUP zastępuje zewnętrzny rezystor podciągający
#define WIND_SPEED_PIN 4
// Musi być zgodne z PULSES_PER_REV i RPM_PER_MPS w anemometer.chip.c -
// to ta sama kalibracja fizycznego wirnika, więc obie strony (symulacja i firmware) muszą się zgadzać, inaczej przeliczenie na m/s będzie złe
#define PULSES_PER_REV 4
#define RPM_PER_MPS 20.0

volatile uint32_t windPulseCount = 0;
unsigned long lastWindCalcMillis = 0;
const unsigned long windCalcIntervalMs = 1000;  // okno pomiaru częstotliwości impulsów
float windSpeedMps = 0;

void IRAM_ATTR onWindPulse() {
  windPulseCount++;
}

void updateWindSpeed() {
  unsigned long now = millis();
  unsigned long dt = now - lastWindCalcMillis;
  if (dt < windCalcIntervalMs) {
    return;  // za wcześnie - czekamy na koniec okna pomiarowego
  }
  noInterrupts();
  uint32_t pulses = windPulseCount;
  windPulseCount = 0;
  interrupts();
  float freqHz = pulses / (dt / 1000.0f);
  float rpm = freqHz * 60.0f / PULSES_PER_REV;
  windSpeedMps = rpm / RPM_PER_MPS;
  lastWindCalcMillis = now;
}
// TEMPERATURA / CIŚNIENIE / WILGOTNOŚĆ (BME280)
// Adres 0x76 - zgodny z naszym bme280.chip.c przy pinie SDO zwartym do masy (INPUT_PULLDOWN w