diff --git a/AGENTS.md b/AGENTS.md index 67dba00..dcb6ec0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,6 +6,7 @@ This repository contains a small ESP8266/ESP32 Arduino project for monitoring wa - `arduino/arduino.ino` contains the Arduino sketch and main application logic. - `server/log.php` accepts measurement POST requests and appends them as JSON Lines. +- `server/data-checker.php` is intended for hourly CRON runs and checks whether recent measurements are still being written. - `server/functions.inc.php` contains shared PHP helpers, including JSON responses, HTTP requests, and Telegram notifications. - `data/YYYY.jsonl` is created at runtime for logged measurements and should not be treated as source code. - `README.md` gives the high-level project purpose. @@ -30,6 +31,7 @@ arduino-cli upload -p COM3 --fqbn esp32:esp32:esp32 arduino arduino-cli monitor -p COM3 -c baudrate=115200 php -l server/log.php +php -l server/data-checker.php php -l server/functions.inc.php ``` @@ -74,10 +76,13 @@ Before committing firmware changes: Before committing server changes: - Run `php -l server/log.php`. +- Run `php -l server/data-checker.php` when the CRON checker changes. - Run `php -l server/functions.inc.php` when shared helpers change. - Test that non-POST requests return HTTP 405 with `Allow: POST`. - Test a form POST such as `level1=1&level2=0&level3=0&level4=1`. - Verify that a single compact JSON object is appended to `data/YYYY.jsonl`. +- Verify the CRON checker stays silent when `data/YYYY.jsonl` is missing, empty, younger than 45 minutes, or older than 3 hours and 45 minutes. +- Verify the CRON checker walks backward to the nearest valid JSON line when the last line is invalid. - For notification changes, verify that Telegram messages are sent only when `level1..level4` differ from the previous saved measurement. - Verify invalid level combinations such as `0100`, `1010`, and `1101` produce the measurement error notification without causing an HTTP error. diff --git a/server/data-checker.php b/server/data-checker.php new file mode 100644 index 0000000..4f98eb8 --- /dev/null +++ b/server/data-checker.php @@ -0,0 +1,77 @@ += 0; $i--) { + $record = json_decode($lines[$i], true); + if (is_array($record) && json_last_error() === JSON_ERROR_NONE) { + return $record; + } + } + + return null; +} + +function parseRecordTime(array $record): ?DateTimeImmutable +{ + if (!isset($record['timestamp']) || !is_string($record['timestamp'])) { + return null; + } + + try { + return new DateTimeImmutable($record['timestamp']); + } catch (Throwable $e) { + error_log('Invalid data timestamp: ' . $e->getMessage()); + return null; + } +} + +function formatLevels(array $record): string +{ + $values = []; + foreach (['level1', 'level2', 'level3', 'level4'] as $name) { + $values[] = $name . '=' . (isset($record[$name]) ? (int) $record[$name] : 0); + } + + return implode(', ', $values); +} + +$record = loadLastValidRecord(DATA_JSONL_FILEPATH); +if ($record === null) { + exit(0); +} + +$recordTime = parseRecordTime($record); +if ($recordTime === null) { + exit(0); +} + +$ageSeconds = time() - $recordTime->getTimestamp(); +if ($ageSeconds <= MIN_AGE_SECONDS || $ageSeconds >= MAX_AGE_SECONDS) { + exit(0); +} + +$message = sprintf( + 'Nebola zaznamenaná nová hodnota hladiny kondenzu, posledná získaná hodnota je z %s (%s). Toto upozornenie príde len 3x, potom sa už nekontroluje.', + $recordTime->format('Y-m-d H:i:s'), + formatLevels($record) +); + +notifyUsers($message); diff --git a/server/functions.inc.php b/server/functions.inc.php index 9ffa30a..f45b392 100644 --- a/server/functions.inc.php +++ b/server/functions.inc.php @@ -1,5 +1,7 @@