pridany zdrojak pre arduino a AGENTS.md

This commit is contained in:
2026-06-24 02:21:24 +02:00
parent ad4309de9d
commit 24849d308d
2 changed files with 321 additions and 0 deletions

76
AGENTS.md Normal file
View File

@ -0,0 +1,76 @@
# Repository Guidelines
## Project Structure & Module Organization
This repository contains a small ESP8266/ESP32 Arduino project for monitoring water level with conductive electrodes.
- `arduino/arduino.ino` contains the Arduino sketch and main application logic.
- `README.md` gives the high-level project purpose.
- `LICENSE` contains licensing information.
- `.agents/` is reserved for agent/tooling metadata and should not be treated as firmware source.
Keep Arduino source files inside the `arduino/` sketch directory so Arduino IDE can open and build the project correctly.
## Build, Test, and Development Commands
Use Arduino IDE or `arduino-cli` with the ESP8266 or ESP32 board package installed.
Examples:
```sh
arduino-cli compile --fqbn esp8266:esp8266:nodemcuv2 arduino
arduino-cli upload -p COM3 --fqbn esp8266:esp8266:nodemcuv2 arduino
arduino-cli monitor -p COM3 -c baudrate=115200
arduino-cli compile --fqbn esp32:esp32:esp32 arduino
arduino-cli upload -p COM3 --fqbn esp32:esp32:esp32 arduino
arduino-cli monitor -p COM3 -c baudrate=115200
```
- `compile` verifies the sketch builds for the selected board.
- `upload` flashes the firmware to the connected board.
- `monitor` opens the serial console used by debug output.
Adjust `--fqbn` and `COM3` for the actual board and port.
## Coding Style & Naming Conventions
Write C++ compatible with Arduino IDE and the ESP8266/ESP32 cores. Use two-space indentation, braces on the same line, and descriptive names.
- Constants: uppercase or clearly prefixed names, for example `PIN_LEVEL1`, `SLEEP_TIME_SEC`.
- Structs and types: PascalCase, for example `WaterLevels`.
- Functions: lower camelCase, for example `readLevels()` and `connectWifi()`.
Prefer small functions with one responsibility. Keep hardware pins, URLs, timings, and debug flags as constants near the top of the sketch.
## Hardware Notes
For ESP8266 conductive level sensing, use external pull-down resistors from each `PIN_LEVEL1..4` input to `GND`. The common electrode is driven to positive voltage only during measurement.
Avoid ESP8266 boot/strap pins for level inputs when possible, especially `GPIO0`, `GPIO2`, and `GPIO15`. Also avoid `GPIO1`/`GPIO3` unless intentionally sharing the serial port. Prefer ordinary GPIO pins such as `GPIO5`, `GPIO4`, `GPIO14`, `GPIO12`, or `GPIO13`, depending on the board and wiring.
## Testing Guidelines
There is no automated test framework in this repository. Validate changes by compiling the sketch and testing on hardware.
Before committing firmware changes:
- Compile for the target ESP8266 or ESP32 board.
- Test `DEBUG == 1` for local level readings without Wi-Fi.
- Test `DEBUG == 2` for repeated Wi-Fi POST requests.
- Test `DEBUG == 0` for production sleep/wake behavior.
## Commit & Pull Request Guidelines
Current Git history is minimal and uses a simple message such as `Initial commit`. Keep future commits short, imperative, and specific, for example `Add WiFi timeout handling`.
Pull requests should include:
- A brief description of firmware behavior changed.
- Board model and Arduino ESP8266/ESP32 core version used for testing.
- Serial output or screenshots when debugging behavior changes.
- Any required configuration changes, especially Wi-Fi, server URL, or pin mapping.
## Security & Configuration Tips
Avoid committing real Wi-Fi passwords or private server endpoints when possible. For shared changes, replace secrets with placeholders and document required local values.

245
arduino/arduino.ino Normal file
View File

@ -0,0 +1,245 @@
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
#elif defined(ESP32)
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <esp_sleep.h>
#else
#error "This sketch supports ESP8266 and ESP32 boards only."
#endif
const int PIN_COMMON_ELECTRODE = 13; // GPIO13 / D7
const int PIN_LEVEL1 = 5; // GPIO5 / D1 - najnizsia hladina
const int PIN_LEVEL2 = 4; // GPIO4 / D2
const int PIN_LEVEL3 = 14; // GPIO14 / D5
const int PIN_LEVEL4 = 12; // GPIO12 / D6 - najvyssia hladina
const int DEBUG = 1;
const char WIFI_SSID[] = "TP-Link_DD1E";
const char WIFI_PASS[] = "33784120";
const unsigned long SLEEP_TIME_SEC = 1800;
const char URL_LOG[] = "https://vihorlat.tpsoft.org/hladinac/server/log.php";
const unsigned long WIFI_TIMEOUT_MS = 15000;
const unsigned long MEASUREMENT_STABILIZE_MS = 50;
struct WaterLevels {
int level1;
int level2;
int level3;
int level4;
};
void initPins();
WaterLevels readLevels();
void printLevels(const WaterLevels &levels);
String buildPostBody(const WaterLevels &levels);
bool connectWifi();
bool sendLevelsToServer(const WaterLevels &levels);
void enterDeepSleep();
void setupLevelPin(int pin);
void setCommonElectrodeOn();
void setCommonElectrodeOff();
int readLevelPin(int pin);
void setup() {
Serial.begin(115200);
delay(200);
Serial.println("Hladinac v0.3 started.");
initPins();
if (DEBUG == 0) {
WaterLevels levels = readLevels();
printLevels(levels);
if (connectWifi()) {
sendLevelsToServer(levels);
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
} else {
Serial.println("WiFi connection failed, skipping upload.");
}
enterDeepSleep();
} else if (DEBUG == 2) {
connectWifi();
}
}
void loop() {
if (DEBUG == 1) {
WaterLevels levels = readLevels();
printLevels(levels);
delay(1000);
} else if (DEBUG == 2) {
WaterLevels levels = readLevels();
printLevels(levels);
if (WiFi.status() != WL_CONNECTED) {
connectWifi();
}
sendLevelsToServer(levels);
delay(5000);
}
}
void initPins() {
pinMode(PIN_COMMON_ELECTRODE, OUTPUT);
setCommonElectrodeOff();
setupLevelPin(PIN_LEVEL1);
setupLevelPin(PIN_LEVEL2);
setupLevelPin(PIN_LEVEL3);
setupLevelPin(PIN_LEVEL4);
}
void setupLevelPin(int pin) {
#if defined(ESP32)
pinMode(pin, INPUT_PULLDOWN);
#else
// ESP8266 pouziva externe pull-down rezistory na GND.
pinMode(pin, INPUT);
#endif
}
void setCommonElectrodeOn() {
#if defined(ESP8266)
digitalWrite(PIN_COMMON_ELECTRODE, HIGH);
#else
digitalWrite(PIN_COMMON_ELECTRODE, HIGH);
#endif
}
void setCommonElectrodeOff() {
#if defined(ESP8266)
digitalWrite(PIN_COMMON_ELECTRODE, LOW);
#else
digitalWrite(PIN_COMMON_ELECTRODE, LOW);
#endif
}
int readLevelPin(int pin) {
#if defined(ESP8266)
return digitalRead(pin) == HIGH ? 1 : 0;
#else
return digitalRead(pin) == HIGH ? 1 : 0;
#endif
}
WaterLevels readLevels() {
WaterLevels levels;
// Spolocna elektroda je zapnuta iba pocas merania, aby sa znizila korozia.
setCommonElectrodeOn();
delay(MEASUREMENT_STABILIZE_MS);
levels.level1 = readLevelPin(PIN_LEVEL1);
levels.level2 = readLevelPin(PIN_LEVEL2);
levels.level3 = readLevelPin(PIN_LEVEL3);
levels.level4 = readLevelPin(PIN_LEVEL4);
setCommonElectrodeOff();
return levels;
}
void printLevels(const WaterLevels &levels) {
Serial.print("level1=");
Serial.print(levels.level1);
Serial.print(" level2=");
Serial.print(levels.level2);
Serial.print(" level3=");
Serial.print(levels.level3);
Serial.print(" level4=");
Serial.println(levels.level4);
}
String buildPostBody(const WaterLevels &levels) {
String body = "level1=" + String(levels.level1);
body += "&level2=" + String(levels.level2);
body += "&level3=" + String(levels.level3);
body += "&level4=" + String(levels.level4);
return body;
}
bool connectWifi() {
if (WiFi.status() == WL_CONNECTED) {
return true;
}
Serial.print("Connecting to WiFi");
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
unsigned long startedAt = millis();
while (WiFi.status() != WL_CONNECTED && millis() - startedAt < WIFI_TIMEOUT_MS) {
delay(500);
Serial.print(".");
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println();
Serial.print("WiFi connected, IP=");
Serial.println(WiFi.localIP());
return true;
}
Serial.println();
Serial.println("WiFi connection timeout.");
return false;
}
bool sendLevelsToServer(const WaterLevels &levels) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Cannot send data, WiFi is not connected.");
return false;
}
#if defined(ESP8266)
BearSSL::WiFiClientSecure client;
#else
WiFiClientSecure client;
#endif
client.setInsecure();
HTTPClient http;
if (!http.begin(client, URL_LOG)) {
Serial.println("HTTP begin failed.");
return false;
}
String body = buildPostBody(levels);
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
int httpCode = http.POST(body);
if (httpCode > 0) {
Serial.print("POST sent, HTTP code=");
Serial.println(httpCode);
} else {
Serial.print("POST failed: ");
Serial.println(http.errorToString(httpCode));
}
http.end();
return httpCode > 0 && httpCode < 400;
}
void enterDeepSleep() {
Serial.print("Entering deep sleep for ");
Serial.print(SLEEP_TIME_SEC);
Serial.println(" seconds.");
Serial.flush();
#if defined(ESP8266)
ESP.deepSleep((uint64_t)SLEEP_TIME_SEC * 1000000ULL);
#else
esp_sleep_enable_timer_wakeup((uint64_t)SLEEP_TIME_SEC * 1000000ULL);
esp_deep_sleep_start();
#endif
}