pridana kontrola zmien hladiny a odosielanie notifikacie na Telegram
This commit is contained in:
@ -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/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.
|
||||
- `LICENSE` contains licensing information.
|
||||
@ -29,12 +30,13 @@ 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/functions.inc.php
|
||||
```
|
||||
|
||||
- `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.
|
||||
- `php -l` checks the PHP logging endpoint for syntax errors.
|
||||
- `php -l` checks the PHP scripts for syntax errors.
|
||||
|
||||
Adjust `--fqbn` and `COM3` for the actual board and port.
|
||||
|
||||
@ -50,6 +52,8 @@ Prefer small functions with one responsibility. Keep hardware pins, URLs, timing
|
||||
|
||||
For PHP scripts, keep them framework-free unless the project grows. Return JSON responses, use explicit HTTP status codes, and keep generated log files under `data/`.
|
||||
|
||||
Keep shared PHP helpers in `server/functions.inc.php`. Use the existing `telegram()` helper for Telegram notifications, and wrap notification calls so delivery failures do not change the HTTP response or stop measurement logging.
|
||||
|
||||
## 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.
|
||||
@ -70,9 +74,12 @@ Before committing firmware changes:
|
||||
Before committing server changes:
|
||||
|
||||
- Run `php -l server/log.php`.
|
||||
- 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`.
|
||||
- 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.
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
|
||||
|
||||
61
server/functions.inc.php
Normal file
61
server/functions.inc.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
function respondJson(int $statusCode, array $payload): void
|
||||
{
|
||||
http_response_code($statusCode);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode($payload) . PHP_EOL;
|
||||
}
|
||||
|
||||
function get_curl(string $url, ?array $postdata = null, ?string $cookiedata = null, int $timeout = 60): string|bool
|
||||
{
|
||||
if (! function_exists('curl_init')) {
|
||||
trigger_error('CURL not installed in PHP');
|
||||
}
|
||||
$url = trim($url);
|
||||
$ch = curl_init();
|
||||
$res = curl_setopt($ch, CURLOPT_URL, $url);
|
||||
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
|
||||
curl_setopt($ch, CURLOPT_HEADER, 0);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
if (!is_null($postdata)) {
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
|
||||
}
|
||||
if (!is_null($cookiedata)) {
|
||||
curl_setopt($ch, CURLOPT_COOKIE, $cookiedata);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla');
|
||||
$ret_data = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
//print_r($ret_data);
|
||||
if (is_null($ret_data)) {
|
||||
trigger_error('Error WS: ' . curl_errno($ch) . " - " . curl_error($ch));
|
||||
}
|
||||
return $ret_data;
|
||||
}
|
||||
|
||||
function telegram(string $to, string $message): string|bool
|
||||
{
|
||||
$json = get_curl('https://telegram.tpsoft.org/sendMessage.php', array('to' => $to, 'message' => $message));
|
||||
return json_encode($json, true);
|
||||
}
|
||||
|
||||
function notifyUsers(string $message): void
|
||||
{
|
||||
foreach (['igor', 'veronika'] as $user) {
|
||||
try {
|
||||
set_error_handler(static function (int $severity, string $errorMessage): bool {
|
||||
throw new ErrorException($errorMessage, 0, $severity);
|
||||
});
|
||||
telegram($user, $message);
|
||||
} catch (Throwable $e) {
|
||||
error_log('Telegram notification failed for ' . $user . ': ' . $e->getMessage());
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,11 +2,72 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
function respondJson(int $statusCode, array $payload): void
|
||||
require_once __DIR__.'/functions.inc.php';
|
||||
|
||||
function loadPreviousRecord(string $filename): ?array
|
||||
{
|
||||
http_response_code($statusCode);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode($payload) . PHP_EOL;
|
||||
if (!is_file($filename)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
if ($lines === false || count($lines) < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The current record has already been appended, so the previous one is the line before it.
|
||||
$previous = json_decode($lines[count($lines) - 2], true);
|
||||
if (!is_array($previous)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $previous;
|
||||
}
|
||||
|
||||
function levelsChanged(?array $previous, array $current): bool
|
||||
{
|
||||
if ($previous === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (['level1', 'level2', 'level3', 'level4'] as $name) {
|
||||
if (!array_key_exists($name, $previous) || (int) $previous[$name] !== (int) $current[$name]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isValidLevelState(array $levels): bool
|
||||
{
|
||||
$lowerLevelInactive = false;
|
||||
foreach (['level1', 'level2', 'level3', 'level4'] as $name) {
|
||||
if ((int) $levels[$name] === 0) {
|
||||
$lowerLevelInactive = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($lowerLevelInactive) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function calculateFilledPercent(array $levels): int
|
||||
{
|
||||
$activeLevels = 0;
|
||||
foreach (['level1', 'level2', 'level3', 'level4'] as $name) {
|
||||
if ((int) $levels[$name] !== 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
$activeLevels++;
|
||||
}
|
||||
|
||||
return $activeLevels * 25;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
@ -83,6 +144,23 @@ if ($written === false) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$previousRecord = loadPreviousRecord($filename);
|
||||
if (levelsChanged($previousRecord, $record)) {
|
||||
// Notify only when the level state changed compared to the previous saved measurement.
|
||||
if (!isValidLevelState($record)) {
|
||||
notifyUsers(sprintf(
|
||||
'Chyba merania hladiny kondenzátu klimatizácie (level1=%d, level2=%d, level3=%d, level4=%d)',
|
||||
$record['level1'],
|
||||
$record['level2'],
|
||||
$record['level3'],
|
||||
$record['level4']
|
||||
));
|
||||
} else {
|
||||
$filledPercent = calculateFilledPercent($record);
|
||||
notifyUsers(sprintf('Nádržka kondenzu klimatizácie: %d%%', $filledPercent));
|
||||
}
|
||||
}
|
||||
|
||||
respondJson(200, [
|
||||
'success' => true,
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user