diff --git a/assets/index.html b/assets/index.html
index 34e9759..6d28ed2 100644
--- a/assets/index.html
+++ b/assets/index.html
@@ -257,6 +257,42 @@
.toast-msg { white-space: nowrap; font-size: 0.85rem; padding: 8px 20px;}
}
+ .pump-state {
+ text-align: center;
+ margin: 0.5rem auto 1.2rem auto;
+ padding: 0.4rem 0.8rem;
+ width: fit-content;
+ border-radius: 20px;
+ background: #33373b;
+ font-weight: 700;
+ font-size: 0.85rem;
+ letter-spacing: 1px;
+ color: #959ea6;
+ font-family: monospace;
+ text-transform: uppercase;
+ border: none;
+ transition: 0.15s linear;
+ }
+
+ .pump-state.enabled {
+ background: #00a86b;
+ color: white;
+ text-shadow: 0 0 2px rgba(0,0,0,0.3);
+ animation: pump-glow 1.2s infinite ease;
+ }
+
+ @keyframes pump-glow {
+ 0% {
+ box-shadow: 0 0 0 0 rgba(0, 168, 107, 0.4);
+ }
+ 70% {
+ box-shadow: 0 0 0 6px rgba(0, 168, 107, 0);
+ }
+ 100% {
+ box-shadow: 0 0 0 0 rgba(0, 168, 107, 0);
+ }
+ }
+
footer {
text-align: center;
font-size: 0.7rem;
@@ -275,6 +311,8 @@
+
+
@@ -295,7 +333,7 @@
-
+
✓ Пороги успешно сохранены
@@ -315,6 +353,7 @@
const minSpan = document.getElementById('minThresholdVal');
const maxSpan = document.getElementById('maxThresholdVal');
const pressureDisplay = document.getElementById('currentPressureDisplay');
+ const currentState = document.getElementById('currentPumpState');
const saveBtn = document.getElementById('saveButton');
const toast = document.getElementById('toastMsg');
@@ -510,6 +549,22 @@
ctx.stroke();
}
+ async function fetchState() {
+ try {
+ const response = await fetch('/state');
+ if (!response.ok) {
+ throw new Error('Failed to fetch state');
+ }
+ const data = await response.json();
+ const state = typeof data === 'number' ? data : data.state;
+ if (typeof state === 'number' && !isNaN(state)) {
+ state === 1 ? currentState.classList.add("enabled") : currentState.classList.remove("enabled");
+ }
+ } catch (error) {
+ console.error('Error fetching state:', error);
+ }
+ }
+
async function fetchPressure() {
try {
const response = await fetch('/pressure');
@@ -735,6 +790,7 @@
function startPolling() {
// Запускаем опрос давления каждые 500 мс
pollingInterval = setInterval(fetchPressure, 500);
+ pollingInterval = setInterval(fetchState, 500);
}
function stopPolling() {
diff --git a/dependencies.lock b/dependencies.lock
index 6eeb899..41988f7 100644
--- a/dependencies.lock
+++ b/dependencies.lock
@@ -9,13 +9,24 @@ dependencies:
registry_url: https://components.espressif.com/
type: service
version: 1.7.19~2
+ espressif/mdns:
+ component_hash: 8bcf12e37c58c1d584aef32a02b92548124c7a3a9fcf548d3235c844a035e0f0
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=5.0'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.11.1
idf:
source:
type: idf
version: 6.1.0
direct_dependencies:
- espressif/cjson
+- espressif/mdns
- idf
-manifest_hash: 626fd43651c3fd7f446de49c6321e4d29d1ea2ce423ef88701f30386e340d0f8
+manifest_hash: aacec634967d1d3809618f54875956325d8c0200c299b5c0a55b6f3128ef2854
target: esp32
version: 3.0.0
diff --git a/main/idf_component.yml b/main/idf_component.yml
index 7e4db4f..53f7cb9 100644
--- a/main/idf_component.yml
+++ b/main/idf_component.yml
@@ -14,4 +14,5 @@ dependencies:
# # `public` flag doesn't have an effect dependencies of the `main` component.
# # All dependencies of `main` are public by default.
# public: true
- espressif/cjson: '*'
+ espressif/cjson: '>=1.7.0'
+ espressif/mdns: '>=1.11.0'
diff --git a/main/main.c b/main/main.c
index 39b0ea5..6735abb 100644
--- a/main/main.c
+++ b/main/main.c
@@ -20,6 +20,7 @@
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "esp_task_wdt.h"
+#include "mdns.h"
#include "lwip/inet.h"
#include "sdkconfig.h"
@@ -57,6 +58,8 @@
#define PRIORITY_CONTROL 2
#define PRIORITY_SENSOR 3
+#define MDNS_DOMAIN "pumpctl"
+
static adc_oneshot_unit_handle_t adc_handle;
static adc_cali_handle_t cali_handle;
static bool is_calibrated = false;
@@ -124,6 +127,20 @@ static esp_err_t send_json_response(httpd_req_t *req, const char *format, ...) {
return ESP_OK;
}
+esp_err_t start_mdns_service() {
+ esp_err_t err = mdns_init();
+ if (err) {
+ return err;
+ }
+
+ mdns_hostname_set(MDNS_DOMAIN);
+ mdns_instance_name_set("Thek4n PumpController");
+
+ mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0);
+
+ return ESP_OK;
+}
+
esp_err_t adc_init(void) {
adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = ADC_UNIT_1,
@@ -163,7 +180,7 @@ esp_err_t adc_init(void) {
static esp_err_t pump_init(void) {
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << CONFIG_PUMP_PIN),
- .mode = GPIO_MODE_OUTPUT,
+ .mode = GPIO_MODE_INPUT_OUTPUT,
.intr_type = GPIO_INTR_DISABLE,
.pull_down_en = 1,
.pull_up_en = 0,
@@ -231,6 +248,12 @@ static esp_err_t current_pressure_handler(httpd_req_t *req) {
return send_json_response(req, "{\"value\":%d}", sensor_value);
}
+static esp_err_t pump_state_handler(httpd_req_t *req) {
+ int pump_enabled = gpio_get_level(CONFIG_PUMP_PIN);
+
+ return send_json_response(req, "{\"state\":%d}", pump_enabled);
+}
+
static esp_err_t save_thresholds_handler(httpd_req_t *req) {
char *content = NULL;
if (receive_http_content(req, &content) != ESP_OK) {
@@ -440,6 +463,16 @@ static void register_http_handlers(httpd_handle_t server) {
ESP_LOGE(TAG, "Failed to register GET /pressure handler");
}
+ httpd_uri_t pump_state = {
+ .uri = "/state",
+ .method = HTTP_GET,
+ .handler = pump_state_handler,
+ .user_ctx = NULL
+ };
+ if (httpd_register_uri_handler(server, &pump_state) != ESP_OK) {
+ ESP_LOGE(TAG, "Failed to register GET /state handler");
+ }
+
httpd_uri_t get_thresholds = {
.uri = "/thresholds",
.method = HTTP_GET,
@@ -532,11 +565,14 @@ void app_main(void) {
}
ESP_ERROR_CHECK(ret);
+
load_thresholds_from_nvs();
ESP_ERROR_CHECK(adc_init());
ESP_ERROR_CHECK(pump_init());
wifi_init_softap();
+ // ESP_ERROR_CHECK(start_mdns_service());
+
vTaskDelay(pdMS_TO_TICKS(1000));
xTaskCreate(vReadSensorTask, "read_sensor", 2048, NULL, PRIORITY_SENSOR, NULL);