feat: pump state

This commit is contained in:
thek4n 2026-06-05 23:45:32 +03:00
parent c13b47a276
commit ef4cdc53a2
4 changed files with 108 additions and 4 deletions

View File

@ -257,6 +257,42 @@
.toast-msg { white-space: nowrap; font-size: 0.85rem; padding: 8px 20px;} .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 { footer {
text-align: center; text-align: center;
font-size: 0.7rem; font-size: 0.7rem;
@ -275,6 +311,8 @@
<div class="value-wrapper"> <div class="value-wrapper">
<div class="pressure-value" id="currentPressureDisplay">0.0 атм</div> <div class="pressure-value" id="currentPressureDisplay">0.0 атм</div>
</div> </div>
<div class="pump-state" id="currentPumpState"></div>
<div class="sliders-panel"> <div class="sliders-panel">
<div class="slider-group"> <div class="slider-group">
@ -295,7 +333,7 @@
<button class="save-btn" id="saveButton">💾 СОХРАНИТЬ УСТАНОВКИ</button> <button class="save-btn" id="saveButton">💾 СОХРАНИТЬ УСТАНОВКИ</button>
</div> </div>
<footer> IoT контроллер давления | © Vladislav Kan &lt;thek4n@yandex.ru&gt;</footer> <footer>⚡IoT контроллер давления | © Vladislav Kan &lt;thek4n@yandex.ru&gt;</footer>
</div> </div>
<div id="toastMsg" class="toast-msg">✓ Пороги успешно сохранены</div> <div id="toastMsg" class="toast-msg">✓ Пороги успешно сохранены</div>
@ -315,6 +353,7 @@
const minSpan = document.getElementById('minThresholdVal'); const minSpan = document.getElementById('minThresholdVal');
const maxSpan = document.getElementById('maxThresholdVal'); const maxSpan = document.getElementById('maxThresholdVal');
const pressureDisplay = document.getElementById('currentPressureDisplay'); const pressureDisplay = document.getElementById('currentPressureDisplay');
const currentState = document.getElementById('currentPumpState');
const saveBtn = document.getElementById('saveButton'); const saveBtn = document.getElementById('saveButton');
const toast = document.getElementById('toastMsg'); const toast = document.getElementById('toastMsg');
@ -510,6 +549,22 @@
ctx.stroke(); 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() { async function fetchPressure() {
try { try {
const response = await fetch('/pressure'); const response = await fetch('/pressure');
@ -735,6 +790,7 @@
function startPolling() { function startPolling() {
// Запускаем опрос давления каждые 500 мс // Запускаем опрос давления каждые 500 мс
pollingInterval = setInterval(fetchPressure, 500); pollingInterval = setInterval(fetchPressure, 500);
pollingInterval = setInterval(fetchState, 500);
} }
function stopPolling() { function stopPolling() {

View File

@ -9,13 +9,24 @@ dependencies:
registry_url: https://components.espressif.com/ registry_url: https://components.espressif.com/
type: service type: service
version: 1.7.19~2 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: idf:
source: source:
type: idf type: idf
version: 6.1.0 version: 6.1.0
direct_dependencies: direct_dependencies:
- espressif/cjson - espressif/cjson
- espressif/mdns
- idf - idf
manifest_hash: 626fd43651c3fd7f446de49c6321e4d29d1ea2ce423ef88701f30386e340d0f8 manifest_hash: aacec634967d1d3809618f54875956325d8c0200c299b5c0a55b6f3128ef2854
target: esp32 target: esp32
version: 3.0.0 version: 3.0.0

View File

@ -14,4 +14,5 @@ dependencies:
# # `public` flag doesn't have an effect dependencies of the `main` component. # # `public` flag doesn't have an effect dependencies of the `main` component.
# # All dependencies of `main` are public by default. # # All dependencies of `main` are public by default.
# public: true # public: true
espressif/cjson: '*' espressif/cjson: '>=1.7.0'
espressif/mdns: '>=1.11.0'

View File

@ -20,6 +20,7 @@
#include "esp_adc/adc_cali.h" #include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h" #include "esp_adc/adc_cali_scheme.h"
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "mdns.h"
#include "lwip/inet.h" #include "lwip/inet.h"
#include "sdkconfig.h" #include "sdkconfig.h"
@ -57,6 +58,8 @@
#define PRIORITY_CONTROL 2 #define PRIORITY_CONTROL 2
#define PRIORITY_SENSOR 3 #define PRIORITY_SENSOR 3
#define MDNS_DOMAIN "pumpctl"
static adc_oneshot_unit_handle_t adc_handle; static adc_oneshot_unit_handle_t adc_handle;
static adc_cali_handle_t cali_handle; static adc_cali_handle_t cali_handle;
static bool is_calibrated = false; 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; 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) { esp_err_t adc_init(void) {
adc_oneshot_unit_init_cfg_t init_config = { adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = ADC_UNIT_1, .unit_id = ADC_UNIT_1,
@ -163,7 +180,7 @@ esp_err_t adc_init(void) {
static esp_err_t pump_init(void) { static esp_err_t pump_init(void) {
gpio_config_t io_conf = { gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << CONFIG_PUMP_PIN), .pin_bit_mask = (1ULL << CONFIG_PUMP_PIN),
.mode = GPIO_MODE_OUTPUT, .mode = GPIO_MODE_INPUT_OUTPUT,
.intr_type = GPIO_INTR_DISABLE, .intr_type = GPIO_INTR_DISABLE,
.pull_down_en = 1, .pull_down_en = 1,
.pull_up_en = 0, .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); 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) { static esp_err_t save_thresholds_handler(httpd_req_t *req) {
char *content = NULL; char *content = NULL;
if (receive_http_content(req, &content) != ESP_OK) { 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"); 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 = { httpd_uri_t get_thresholds = {
.uri = "/thresholds", .uri = "/thresholds",
.method = HTTP_GET, .method = HTTP_GET,
@ -532,11 +565,14 @@ void app_main(void) {
} }
ESP_ERROR_CHECK(ret); ESP_ERROR_CHECK(ret);
load_thresholds_from_nvs(); load_thresholds_from_nvs();
ESP_ERROR_CHECK(adc_init()); ESP_ERROR_CHECK(adc_init());
ESP_ERROR_CHECK(pump_init()); ESP_ERROR_CHECK(pump_init());
wifi_init_softap(); wifi_init_softap();
// ESP_ERROR_CHECK(start_mdns_service());
vTaskDelay(pdMS_TO_TICKS(1000)); vTaskDelay(pdMS_TO_TICKS(1000));
xTaskCreate(vReadSensorTask, "read_sensor", 2048, NULL, PRIORITY_SENSOR, NULL); xTaskCreate(vReadSensorTask, "read_sensor", 2048, NULL, PRIORITY_SENSOR, NULL);