commit 1eee37beb9e2f05b84d59c0a8bf93fe989e9e17f
parent eccbcb8a5ed2d4f07254132a6fcebaad8ac95ea4
Author: Martin Kloeckner <mjkloeckner@gmail.com>
Date: Sat, 11 Apr 2026 21:43:40 -0300
Add tmeperature controls
Diffstat:
| M | data/index.html | | | 98 | ++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------- |
| M | data/main.js | | | 35 | +++++++++++++++++++++++++++++++++-- |
| M | data/style.css | | | 103 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- |
| M | platformio.ini | | | 4 | ++++ |
| M | src/main.cpp | | | 108 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- |
5 files changed, 281 insertions(+), 67 deletions(-)
diff --git a/data/index.html b/data/index.html
@@ -1,47 +1,79 @@
<!DOCTYPE html>
<html>
<head>
- <title>ESP8266 Web Server</title>
+ <title>Derretidor de miel</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta charset="UTF-8">
<link rel="icon" href="data:,">
<link rel="stylesheet" type="text/css" href="style.css">
<script type="text/javascript" src="main.js"></script>
</head>
<body>
<div id="main-div">
- <h1 id="title">ESP8266 Remote Panel</h1>
+ <h1 id="title">Derretidor de miel</h1>
<div id="buttons-div">
- <div id="main-toggle-div" onclick="handle_click('main-toggle')">
- <table>
- <tr style="vertical-align: bottom;">
- <td>
- Main output enabled
- </td>
- <td id="main-checkbox-td">
- <div id="main-checkbox" checked="">
- <svg id="checkmark-svg"
- version="1.0"
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 64.000000 64.000000"
- preserveAspectRatio="xMidYMid meet">
- <g transform="translate(0.000000,64.000000) scale(0.100000,-0.100000)"
- fill="currentColor" stroke="currentColor">
- <path d="M380 419 l-142 -211 -67 66 c-38 38 -75 66 -87 66 -25 0 -84 -60 -84
- -86 0 -11 45 -65 113 -132 121 -121 145 -132 184 -89 49 54 343 502 343 523 0
- 27 -62 74 -96 74 -16 0 -53 -48 -164 -211z"/>
- </g>
- </svg>
- </div>
- </td>
- </tr>
- </table>
+ <div id="main">
+ <div id="main-toggle" onclick="handle_click('main-toggle')">
+ <table>
+ <tr style="vertical-align: bottom;">
+ <td>
+ Calefactor activo
+ </td>
+ <td id="main-checkbox-td">
+ <div id="main-checkbox" checked="">
+ <svg id="checkmark-svg"
+ version="1.0"
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 64.000000 64.000000"
+ preserveAspectRatio="xMidYMid meet">
+ <g transform="translate(0.000000,64.000000) scale(0.100000,-0.100000)"
+ fill="currentColor" stroke="currentColor">
+ <path d="M380 419 l-142 -211 -67 66 c-38 38 -75 66 -87 66 -25 0 -84 -60 -84
+ -86 0 -11 45 -65 113 -132 121 -121 145 -132 184 -89 49 54 343 502 343 523 0
+ 27 -62 74 -96 74 -16 0 -53 -48 -164 -211z"/>
+ </g>
+ </svg>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div id="main-sep"></div>
+ <div id="main-now">
+ <table>
+ <tr style="vertical-align: bottom;">
+ <td>
+ Temperatura actual
+ </td>
+ <td id=main-now-value>
+ 0
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div id="main-set">
+ <table>
+ <tr style="vertical-align: bottom;">
+ <td>
+ Temperatura establecida
+ </td>
+ <td>
+ <input id="main-set-value" type="number"
+ value="25" min=0 max="80"/>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div id="main-save-div">
+ <input type="button" value="Aplicar" id="main-save">
+ </div>
</div>
<div id="timer">
<div id="timer-enable" onclick="handle_click('timer-toggle')">
<table>
<tr>
<td>
- Timer enabled
+ Timer activo
</td>
<td id="timer-checkbox-td">
<div id="timer-checkbox" checked="">
@@ -67,7 +99,7 @@
<table>
<tr>
<td>
- From
+ Desde
</td>
<td>
<input id="from-time" type="time" value="18:00"/>
@@ -75,7 +107,7 @@
</tr>
<tr>
<td>
- Until
+ Hasta
</td>
<td>
<input id="to-time" type="time" value="00:00"/>
@@ -84,7 +116,7 @@
</table>
</div>
<div id="timer-save-div">
- <input type="button" value="Save" id="timer-save">
+ <input type="button" value="Aplicar" id="timer-save">
</div>
</div>
</div>
@@ -101,7 +133,7 @@
</tr>
<tr>
<td>
- WiFi Strength
+ WiFi RSSI
</td>
<td>
<div id="wifi-rssi"></div>
@@ -109,7 +141,7 @@
</tr>
<tr>
<td>
- Local IP address
+ Direccion IP local
</td>
<td>
<a id="system-ip-addr"></a>
@@ -117,7 +149,7 @@
</tr>
<tr>
<td>
- System time
+ Reloj del sistema
</td>
<td>
<div id="system-time"></div>
diff --git a/data/main.js b/data/main.js
@@ -2,7 +2,8 @@ var received_data;
var main_checkbox, timer_checkbox;
var time_div, system_ip_addr, wifi_ssid, wifi_rssi;
var system_time, system_time_elem;
-var to_time, from_time, timer_save_button;
+var to_time, from_time, temp_now, temp_set_value;
+var temp_save_button, timer_save_button;
const time_formatter = new Intl.DateTimeFormat('en-GB', {
timeZone: 'America/Argentina/Buenos_Aires',
@@ -18,7 +19,8 @@ const query_types = {
"QUERY_STATUS": 0,
"QUERY_MAIN_OUTPUT_TOGGLE": 1,
"QUERY_TIMER_TOGGLE": 2,
- "QUERY_TIMER_SET_VALUES": 3
+ "QUERY_TIMER_SET_VALUES": 3,
+ "QUERY_TEMP_SET": 4
}
function rssi_to_percentage(rssi) {
@@ -46,6 +48,15 @@ function update_time() {
.replaceAll(",", "") + " GMT-3";
}
+function update_now_temp() {
+ temp_now.textContent = received_data["temp-now"] + "°C";
+}
+
+function update_temp() {
+ temp_now.textContent = received_data["temp-now"] + "°C";
+ temp_set_value.value = received_data["temp-set"];
+}
+
function update_timer() {
from_time.value = received_data["timer"]["from"]["hour"] + ":"
+ received_data["timer"]["from"]["minute"];
@@ -57,6 +68,7 @@ function update_all() {
update_checkbox();
update_time();
update_timer();
+ update_temp();
system_ip_addr.href = received_data["system-ip-addr"];
system_ip_addr.innerHTML = received_data["system-ip-addr"];
@@ -83,6 +95,12 @@ function socket_onmessage_handler(event) {
case "timer":
update_timer();
break;
+ case "temp-values":
+ update_temp();
+ break;
+ case "temp-now-values":
+ update_now_temp();
+ break;
default:
console.log("[SOCKET] received_data: type not known, updating all...");
update_all();
@@ -122,6 +140,14 @@ function timer_set_time() {
socket.send(query_types["QUERY_TIMER_SET_VALUES"] + JSON.stringify(query_json));
}
+function temp_set() {
+ var query_json = new Object();
+
+ query_json.temp_set_point_new = temp_set_value.value.slice(0, 2);
+ socket.send(query_types["QUERY_TEMP_SET"] + JSON.stringify(query_json));
+}
+
+
function query_data() {
main_checkbox = document.getElementById("main-checkbox");
timer_checkbox = document.getElementById("timer-checkbox");
@@ -133,6 +159,11 @@ function query_data() {
from_time = document.getElementById("from-time");
to_time = document.getElementById("to-time");
+ temp_now = document.getElementById("main-now-value");
+ temp_set_value = document.getElementById("main-set-value");
+ temp_save_button = document.getElementById("main-save");
+ temp_save_button.addEventListener( "click", temp_set, false);
+
timer_save_button = document.getElementById("timer-save");
timer_save_button.addEventListener( "click", timer_set_time, false);
diff --git a/data/style.css b/data/style.css
@@ -36,22 +36,58 @@ h1 {
font-size: 36px;
}
-#main-toggle-div {
+#main {
+ /*
margin-bottom: 0.5em;
cursor: pointer;
padding: 1.25em 28px 1.00em 28px;
border-radius: 8px;
border: 1px solid #E3E3E3;
+ */
}
-#timer {
+#main, #timer {
border-radius: 8px;
border: 1px solid #E3E3E3;
}
+#timer {
+ margin-top: 1em;
+}
+
+#main-set,
+#main-toggle,
#timer-enable {
cursor: pointer;
- padding: 27.5px 28px 16px 28px;
+}
+
+#main-now,
+#main-set {
+ font-size: 20px;
+}
+
+#main-now-value {
+ font-family: monospace;
+}
+
+#timer-enable {
+ padding: 28px 28px 12px 28px;
+}
+
+#main-toggle {
+ padding: 28px 28px 12px 28px;
+}
+
+#main-now {
+ padding: 18px 28px 2px 28px;
+}
+
+#main-sep {
+ padding: 0px 28px 0px 28px;
+}
+
+#main-set {
+ padding: 0px 28px 0px 28px;
}
#timer-picker {
@@ -59,7 +95,7 @@ h1 {
font-size: 20px;
}
-#timer-sep {
+#timer-sep, #main-sep {
border-bottom: 1px solid #E3E3E3;
margin: 0 30px 0 30px;
}
@@ -74,12 +110,12 @@ h1 {
background-color: white;
}
-#timer-save-div {
+#timer-save-div, #main-save-div {
padding: 18px 30px 30px 30px;
text-align: center;
}
-#timer-save {
+#timer-save, #main-save {
margin-right: 0px;
box-shadow: none;
border: 1px solid #E3E3E3;
@@ -88,28 +124,54 @@ h1 {
border-radius: 5px;
cursor: pointer;
height: 32px;
- font-size: 14px;
+ font-size: 16px;
width: 100%;
- font-weight: bold;
+ font-weight: normal;
}
-#timer-save:active {
+#timer-save:active, #main-save:active {
background-color: #E3E3E3;
border: none;
}
+#main-set-value {
+ font-size: 18px;
+ font-weight: normal;
+ font-family: monospace;
+ width: 50px;
+ border: 1px solid #E3E3E3;
+ border-radius: 5px;
+ padding: 2px;
+ font-size: 18px;
+ height: 22px;
+
+ /*
+ margin: 0px;
+ border: 1px solid #E3E3E3;
+ cursor: pointer;
+
+ margin-right: 0px;
+ box-shadow: none;
+ background-color: white;
+ border-radius: 5px;
+ cursor: pointer;
+ */
+}
+
@media (hover: hover) and (pointer: fine) {
- #main-toggle-div:hover #main-checkbox,
+ #main-toggle:hover #main-checkbox,
#timer-enable:hover #timer-checkbox,
#from-time:hover, #to-time:hover,
#main-checkbox:hover, #timer-checkbox:hover,
- #timer-save:hover {
+ #main-set-value:hover,
+ #timer-save:hover, #main-save:hover {
border: 1px solid #999999;
}
}
#from-time:focus-visible,
-#to-time:focus-visible {
+#to-time:focus-visible,
+#main-set-value:focus-visible {
border: 1px solid #999999;
outline: none;
}
@@ -206,28 +268,28 @@ h1 {
border: none;
}
- #main-toggle-div, #timer {
+ #main, #timer {
background-color: #232326;
border: none;
}
- #timer-sep {
+ #timer-sep, #main-sep {
border-bottom-color: #3E3E42;
}
- #timer-save {
+ #timer-save, #main-save {
border-color: #999999;
color: white;
background-color: #303033;
border-color: #3E3E42;
}
- #timer-save:active {
+ #timer-save:active, #main-save:active {
background-color: #3E3E42;
border: none;
}
- #from-time, #to-time {
+ #from-time, #to-time, #main-set-value {
background-color: #303033;
color: white;
border-color: #3E3E42;
@@ -244,17 +306,18 @@ h1 {
}
@media (hover: hover) and (pointer: fine) {
- #main-toggle-div:hover #main-checkbox,
+ #main-toggle:hover #main-checkbox,
#timer-enable:hover #timer-checkbox,
#from-time:hover, #to-time:hover,
#main-checkbox:hover, #timer-checkbox:hover,
- #timer-save:hover {
+ #timer-save:hover, #main-save:hover {
border: 1px solid #828282;
}
}
#from-time:focus-visible,
- #to-time:focus-visible {
+ #to-time:focus-visible,
+ #main-set-value:focus-visible {
border: 1px solid #828282;
}
}
diff --git a/platformio.ini b/platformio.ini
@@ -18,3 +18,7 @@ board_build.ldscript = eagle.flash.4m1m.ld
; Set filesystem to LittleFS
board_build.filesystem = littlefs
+
+build_flags =
+ -D WIFI_SSID=\"${sysenv.WIFI_SSID}\"
+ -D WIFI_PASSWD=\"${sysenv.WIFI_PASSWD}\"
diff --git a/src/main.cpp b/src/main.cpp
@@ -11,10 +11,16 @@
#endif
#define REMOTE_LED_PIN 2
-#define WIFI_SSID "abcdefgh"
-#define WIFI_PASSWD "12345678"
#define LOG_ENABLE false
+#ifndef WIFI_SSID
+#define WIFI_SSID "abcdefgh"
+#endif
+
+#ifndef WIFI_PASSWD
+#define WIFI_PASSWD "12345678"
+#endif
+
#if true == LOG_ENABLE
#define LOG(fmt, ...) do { \
Serial.printf(fmt, ##__VA_ARGS__); \
@@ -32,20 +38,25 @@ typedef enum {
TX_DATA_MAIN_OUTPUT_TOGGLE = 'B',
TX_DATA_TIMER_TOGGLE = 'C',
TX_DATA_TIMER_SET_VALUES = 'D',
+ TX_DATA_TEMP_STATUS = 'E',
+ TX_DATA_TEMP_SET = 'F'
} uart_tx_data_e;
typedef enum {
RX_DATA_STATUS_OK = 'A',
RX_DATA_MAIN_OUTPUT_TOGGLE_OK = 'B',
RX_DATA_TIMER_TOGGLE_OK = 'C',
- RX_DATA_TIMER_SET_VALUES_OK = 'D'
+ RX_DATA_TIMER_SET_VALUES_OK = 'D',
+ RX_DATA_TEMP_STATUS_OK = 'E',
+ RX_DATA_TEMP_SET_OK = 'F'
} uart_rx_data_e;
typedef enum {
QUERY_STATUS = 0,
QUERY_MAIN_OUTPUT_TOGGLE,
QUERY_TIMER_TOGGLE,
- QUERY_TIMER_SET_VALUES
+ QUERY_TIMER_SET_VALUES,
+ QUERY_TEMP_SET
} query_type_e;
typedef struct {
@@ -59,11 +70,11 @@ typedef struct {
ESP8266WebServer server(80);
WebSocketsServer web_socket = WebSocketsServer(81);
uint8_t remote_devices, main_output_enabled;
-uint32_t t, system_time_dt;
time_t system_time;
timer_param_t timer, new_timer;
JSONVar data, timer_data;
queue_t uart_queue_tx, uart_queue_rx;
+int16_t temp_now, temp_now_new, temp_set_point, temp_set_point_new;
void setup_wifi();
void setup_websocket();
@@ -154,6 +165,34 @@ void webserver_update_all_clients_timer_values()
web_socket.broadcastTXT(output_data_as_json.c_str());
}
+void webserver_update_all_clients_temp_now_value()
+{
+ JSONVar output_data;
+ String output_data_as_json;
+
+ output_data["type"] = "temp-now-values";
+ output_data["temp-now"] = temp_now;
+
+ // web_socket.broadcastTXT(JSON.stringify(output_data).c_str());
+ output_data_as_json = JSON.stringify(output_data);
+ web_socket.broadcastTXT(output_data_as_json.c_str());
+}
+
+
+void webserver_update_all_clients_temp_values()
+{
+ JSONVar output_data;
+ String output_data_as_json;
+
+ output_data["type"] = "temp-values";
+ output_data["temp-now"] = temp_now;
+ output_data["temp-set"] = temp_set_point;
+
+ // web_socket.broadcastTXT(JSON.stringify(output_data).c_str());
+ output_data_as_json = JSON.stringify(output_data);
+ web_socket.broadcastTXT(output_data_as_json.c_str());
+}
+
void websocket_event_handler(uint8_t num, WStype_t type, uint8_t *payload, size_t len)
{
IPAddress ip;
@@ -229,6 +268,16 @@ void websocket_event_handler(uint8_t num, WStype_t type, uint8_t *payload, size_
break;
+ case QUERY_TEMP_SET: {
+ payload++; // skip query type
+ JSONVar temp_data;
+ temp_data = JSON.parse((char *)payload);
+ temp_set_point_new = (uint8_t)String(temp_data["temp_set_point_new"]).toInt();
+ queue_enqueue(&uart_queue_tx, TX_DATA_TEMP_SET);
+ queue_enqueue(&uart_queue_tx, (uint8_t)temp_set_point_new);
+ }
+ break;
+
default:
break;
}
@@ -328,6 +377,8 @@ void update_data() {
data["wifi-rssi"] = WiFi.RSSI();
update_timer_data();
data["timer"] = timer_data;
+ data["temp-now"] = temp_now;
+ data["temp-set"] = temp_set_point;
}
void uart_rx_handler(void)
@@ -341,9 +392,15 @@ void uart_rx_handler(void)
uint8_t rx_data_type = queue_peek(&uart_queue_rx);
- // Wait for additional data to arrive
if ((rx_data_type == RX_DATA_STATUS_OK) && (queue_count(&uart_queue_rx) < 10))
{
+ // Wait for additional data to arrive
+ return;
+ }
+
+ if ((rx_data_type == RX_DATA_TEMP_STATUS_OK) && (queue_count(&uart_queue_rx) < 2))
+ {
+ // Wait for additional data to arrive
return;
}
@@ -372,6 +429,9 @@ void uart_rx_handler(void)
timer.to_hour = queue_dequeue(&uart_queue_rx);
timer.to_minute = queue_dequeue(&uart_queue_rx);
+ temp_now = queue_dequeue(&uart_queue_rx);
+ temp_set_point = queue_dequeue(&uart_queue_rx);
+
update_data();
data["type"] = "all";
@@ -406,7 +466,28 @@ void uart_rx_handler(void)
break;
+ case RX_DATA_TEMP_SET_OK:
+
+ temp_set_point = temp_set_point_new;
+ webserver_update_all_clients_temp_values();
+
+ break;
+
+ case RX_DATA_TEMP_STATUS_OK:
+
+ temp_now_new = queue_dequeue(&uart_queue_rx);
+ temp_set_point = queue_dequeue(&uart_queue_rx); // discard value
+
+ if (temp_now_new != temp_now)
+ {
+ temp_now = temp_now_new;
+ webserver_update_all_clients_temp_now_value();
+ }
+
+ break;
+
default:
+ queue_dequeue(&uart_queue_rx);
break;
}
}
@@ -435,8 +516,11 @@ void setup()
timer.to_minute = 0;
main_output_enabled = 0;
- t = 0;
- system_time_dt = 0;
+
+ temp_now = 0;
+ temp_now_new = 0;
+ temp_set_point = 0;
+ temp_set_point_new = 0;
time(&system_time); // read the current time
@@ -454,13 +538,13 @@ void setup()
void loop()
{
- if (Serial.available() > 0)
+ while (Serial.available() > 0)
{
int16_t byte = Serial.read();
if (byte >= 0)
{
- queue_enqueue(&uart_queue_rx, byte);
+ queue_enqueue(&uart_queue_rx, (uint8_t)byte);
}
}
@@ -469,10 +553,10 @@ void loop()
uart_rx_handler();
}
- if (!queue_is_empty(&uart_queue_tx))
+ while (!queue_is_empty(&uart_queue_tx))
{
uint8_t value = queue_dequeue(&uart_queue_tx);
- LOG_INFO("Sending byte 0x%2X...\n", value);
+ LOG_INFO("Sending byte 0x%02X...\n", value);
Serial.write(value);
LOG("\n");
}