ESP214/ESP212 and hooks (#999)

* Add expandString to ESP214

* Implement ESP212 for sending text to printer screen (M117)

* Implement hooks for got IP and got DateTime

* Allow finish processing  current stream before adding new one instead of reject

* Add parmeter to expandString to escape space

* Update notifications_service.cpp

* Add sanity check for hooks and autoscript
This commit is contained in:
Luc 2024-02-08 10:32:24 +01:00 committed by GitHub
parent ec7c422f7f
commit 2c1661007d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 228 additions and 39 deletions

View File

@ -124,6 +124,9 @@ label can be: light/framesize/quality/contrast/brightness/saturation/gainceiling
* Get Sensor Value / type/Set Sensor type
`[ESP210]<type=NONE/xxx> <interval=XXX in millisec> json=<no> pwd=<user/admin password>`
* Output to printer screen status
`[ESP212]<Text> json=<no> pwd=<user/admin password>`
* Output to esp screen status
`[ESP214]<Text> json=<no> pwd=<user/admin password>`

View File

@ -104,6 +104,7 @@ Here the scope of right for each authentication level:
| ESP201 | No | No | Get/Set | Get/Set |
| ESP202 | No | No | Get | Get/Set |
| ESP210 | No | No | Get | Get/Set |
| ESP212 | No | No | Set | Set |
| ESP214 | No | No | Set | Set |
| ESP215 | No | No | No | Set |
| ESP220 | No | No | Get | Get |

View File

@ -1292,6 +1292,43 @@ the admin password if authentication is enabled
* `status` status of command, should be `ok`
* `data` content of response, here `ok`
+++
archetype = "section"
title = "[ESP212]"
weight = 800
+++
Output to printer screen status
## Input
`[ESP212]<Text> json=<no> pwd=<admin password>`
* json=no
the output format
can be in JSON or plain text
* pwd=<admin password>
the admin password if authentication is enabled
* Text
* if Text is not empty, it will set the Text
* if Text is empty, it will clear current Text
## Output
- In json format
```json
{
"cmd":"212",
"status":"ok",
"data":"ok"
}
```
* `cmd` Id of requested command, should be `212`
* `status` status of command, should be `ok`
* `data` content of response, here `ok`
+++
archetype = "section"
title = "[ESP214]"
@ -1329,7 +1366,6 @@ the admin password if authentication is enabled
* `status` status of command, should be `ok`
* `data` content of response, here `ok`
+++
archetype = "section"
title = "[ESP215]"

View File

@ -561,10 +561,22 @@
*/
// #define ESP_LUA_INTERPRETER_FEATURE
/* Hook when got IP
* Commands to run on event
* Separate commands with ';'
*/
#define ESP_GOT_IP_HOOK "[ESP212]IP:%ESP_IP%"
/* Hook when got date time
* Commands to run on event
* Separate commands with ';'
*/
#define ESP_GOT_DATE_TIME_HOOK "[ESP212]DATE:%ESP_DATETIME%"
/* Gcode Host Feature
* This feature allows to process Gcode files like macros.
*/
// #define GCODE_HOST_FEATURE
#define GCODE_HOST_FEATURE
/* Settings location
* SETTINGS_IN_EEPROM //ESP8266/ESP32
@ -614,7 +626,7 @@
* Do not modify
************************************/
#if defined(SD_TIMESTAMP_FEATURE) || defined(FILESYSTEM_TIMESTAMP_FEATURE)
#if defined(ESP_GOT_DATE_TIME_HOOK) ||defined(SD_TIMESTAMP_FEATURE) || defined(FILESYSTEM_TIMESTAMP_FEATURE)
#define TIMESTAMP_FEATURE
#endif // SD_TIMESTAMP_FEATURE || FILESYSTEM_TIMESTAMP_FEATURE

View File

@ -102,6 +102,9 @@ const char* help[] = {
"[ESP210](type=NONE/xxx) (interval=xxxx) - display and read/set SENSOR "
"info",
#endif // SENSOR_DEVICE
#if defined(PRINTER_HAS_DISPLAY)
"[ESP212](text) - display (text) to printer screen status",
#endif // PRINTER_HAS_DISPLAY
#if defined(DISPLAY_DEVICE)
"[ESP214](text) - display (text) to ESP screen status",
#if defined(DISPLAY_TOUCH_DRIVER)
@ -240,6 +243,9 @@ const uint cmdlist[] = {
#ifdef SENSOR_DEVICE
210,
#endif // SENSOR_DEVICE
#if defined(PRINTER_HAS_DISPLAY)
212,
#endif // PRINTER_HAS_DISPLAY
#if defined(DISPLAY_DEVICE)
214,
#if defined(DISPLAY_TOUCH_DRIVER)

View File

@ -0,0 +1,61 @@
/*
ESP212.cpp - ESP3D command class
Copyright (c) 2014 Luc Lebosse. All rights reserved.
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "../../include/esp3d_config.h"
#if defined(PRINTER_HAS_DISPLAY)
#include "../../modules/authentication/authentication_service.h"
#include "../../modules/display/display.h"
#include "../esp3d_commands.h"
#include "../esp3d_settings.h"
#include "../esp3d_string.h"
#define COMMAND_ID 212
// Output to printer screen status
//[ESP212]<Text>json=<no> pwd=<user/admin password>
void ESP3DCommands::ESP212(int cmd_params_pos, ESP3DMessage* msg) {
ESP3DClientType target = msg->origin;
ESP3DRequest requestId = msg->request_id;
(void)requestId;
msg->target = target;
msg->origin = ESP3DClientType::command;
bool hasError = false;
String error_msg = "Invalid parameters";
String ok_msg = "ok";
bool json = hasTag(msg, cmd_params_pos, "json");
String tmpstr;
#if defined(AUTHENTICATION_FEATURE)
if (msg->authentication_level == ESP3DAuthenticationLevel::guest) {
msg->authentication_level = ESP3DAuthenticationLevel::not_authenticated;
dispatchAuthenticationError(msg, COMMAND_ID, json);
return;
}
#endif // AUTHENTICATION_FEATURE
tmpstr = get_clean_param(msg, cmd_params_pos);
tmpstr = esp3d_string::expandString(tmpstr.c_str());
hasError = !esp3d_commands.dispatch(tmpstr.c_str(), ESP3DClientType::remote_screen,
no_id, ESP3DMessageType::unique,
ESP3DClientType::system,
ESP3DAuthenticationLevel::admin);
if (!dispatchAnswer(msg, COMMAND_ID, json, hasError,
hasError ? error_msg.c_str() : ok_msg.c_str())) {
esp3d_log_e("Error sending response to clients");
}
}
#endif // PRINTER_HAS_DISPLAY

View File

@ -23,6 +23,7 @@
#include "../../modules/display/display.h"
#include "../esp3d_commands.h"
#include "../esp3d_settings.h"
#include "../esp3d_string.h"
#define COMMAND_ID 214
// Output to esp screen status
@ -46,6 +47,7 @@ void ESP3DCommands::ESP214(int cmd_params_pos, ESP3DMessage* msg) {
}
#endif // AUTHENTICATION_FEATURE
tmpstr = get_clean_param(msg, cmd_params_pos);
tmpstr = esp3d_string::expandString(tmpstr.c_str());
esp3d_display.setStatus(tmpstr.c_str());
if (!dispatchAnswer(msg, COMMAND_ID, json, hasError,
hasError ? error_msg.c_str() : ok_msg.c_str())) {

View File

@ -72,6 +72,9 @@ bool Esp3D::begin() {
BootDelay bd;
ESP3DHal::begin();
ESP3D_LOG_INIT_FN
#if defined(GCODE_HOST_FEATURE)
esp3d_gcode_host.begin();
#endif // GCODE_HOST_FEATURE
#if COMMUNICATION_PROTOCOL == SOCKET_SERIAL
Serial2Socket.enable();
#endif // COMMUNICATION_PROTOCOL == SOCKET_SERIAL

View File

@ -596,6 +596,13 @@ void ESP3DCommands::execute_internal_command(int cmd, int cmd_params_pos,
ESP210(cmd_params_pos, msg);
break;
#endif // #ifdef SENSOR_DEVICE
#if defined (PRINTER_HAS_DISPLAY)
// Output to printer screen status
//[ESP212]<Text>json=<no> pwd=<user/admin password>
case 212:
ESP212(cmd_params_pos, msg);
break;
#endif // PRINTER_HAS_DISPLAY
#if defined(DISPLAY_DEVICE)
// Output to esp screen status
//[ESP214]<Text>pwd=<user password>
@ -1231,6 +1238,10 @@ bool ESP3DCommands::dispatch(ESP3DMessage *msg) {
// currently only echo back no test done on success
// TODO check add is successful
switch (msg->target) {
case ESP3DClientType::no_client:
esp3d_log("No client message");
ESP3DMessageManager::deleteMsg(msg);
break;
#if COMMUNICATION_PROTOCOL == RAW_SERIAL
case ESP3DClientType::serial:
esp3d_log("Serial message");
@ -1528,8 +1539,8 @@ bool ESP3DCommands::dispatch(ESP3DMessage *msg) {
}
break;
default:
esp3d_log_e("No valid target specified %d",
static_cast<uint8_t>(msg->target));
esp3d_log_e("No valid target specified %d for %s",
static_cast<uint8_t>(msg->target), (char *)msg->data);
sendOk = false;
}
// clear message

View File

@ -117,6 +117,9 @@ class ESP3DCommands {
#ifdef DIRECT_PIN_FEATURE
void ESP201(int cmd_params_pos, ESP3DMessage* msg);
#endif // DIRECT_PIN_FEATURE
#if defined(PRINTER_HAS_DISPLAY)
void ESP212(int cmd_params_pos, ESP3DMessage* msg);
#endif // PRINTER_HAS_DISPLAY
#if defined(DISPLAY_DEVICE)
void ESP214(int cmd_params_pos, ESP3DMessage* msg);
#if defined(DISPLAY_TOUCH_DRIVER)

View File

@ -192,7 +192,7 @@ if (c==9 || (c >= 32 && c <= 126) || c>=128) {
return false;
}
const char * esp3d_string::expandString(const char *s){
const char* esp3d_string::expandString(const char* s, bool formatspace) {
static String tmp;
tmp = s;
if (tmp.indexOf("%") != -1) {
@ -204,11 +204,12 @@ const char * esp3d_string::expandString(const char *s){
tmp.replace("%ESP_NAME%", "???");
#endif // WIFI_FEATURE || ETH_FEATURE
#if defined(TIMESTAMP_FEATURE)
tmp.replace("%ESP_DATETIME%", timeService.getCurrentTime());
String dt = timeService.getCurrentTime();
if (formatspace) dt.replace(" ", "\\ ");
tmp.replace("%ESP_DATETIME%", dt.c_str());
#else
tmp.replace("%ESP_DATETIME%", "???");
#endif // TIMESTAMP_FEATURE
}
return tmp.c_str();
}

View File

@ -28,7 +28,7 @@ const char* getContentType(const char* filename);
const char* encodeString(const char* s);
const char* formatBytes(uint64_t bytes);
bool isPrintableChar(char c);
const char * expandString(const char *s);
const char * expandString(const char *s, bool formatspace = false);
} // namespace esp3d_string
#endif //_ESP3D_STRING_H

View File

@ -20,7 +20,7 @@
#ifndef _SANITY_ESP3D_H
#define _SANITY_ESP3D_H
#if not defined(ESP_NO_SANITY_CHECK)
/**************************
* Settings
* ***********************/
@ -39,7 +39,9 @@
#if defined(ESP_LOG_FEATURE)
#if ESP_LOG_FEATURE == ESP_SERIAL_OUTPUT
#if not defined(ESP_NO_SANITY_CHECK)
#warning You use same serial for output and log
#endif // SANITY_ESP3D_H
#endif // ESP_LOG_FEATURE == ESP_SERIAL_OUTPUT
#if (ESP_LOG_FEATURE == LOG_OUTPUT_SERIAL2) && defined(ARDUINO_ARCH_ESP8266)
#error Serial 2 is not available in ESP8266 for log
@ -88,8 +90,19 @@
#endif
/**************************
* Time
* Hooks
* ***********************/
#if defined(ESP_AUTOSTART_SCRIPT) || defined(ESP_AUTOSTART_SCRIPT_FILE) || defined(ESP_GOT_IP_HOOK) || defined(ESP_GOT_DATE_TIME_HOOK)
#ifndef GCODE_HOST_FEATURE
#error GCODE_HOST_FEATURE is necessary for ESP_AUTOSTART_SCRIPT/ESP_AUTOSTART_SCRIPT_FILE/ESP_GOT_IP_HOOK/ESP_GOT_DATE_TIME_HOOK
#endif //ifndef GCODE_HOST_FEATURE
#endif //#if defined(ESP_AUTOSTART_SCRIPT) || defined(ESP_AUTOSTART_SCRIPT_FILE) || defined(ESP_GOT_IP_HOOK) || defined(ESP_GOT_DATE_TIME_HOOK)
#if defined(ESP_GOT_IP_HOOK) || defined(ESP_GOT_DATE_TIME_HOOK)
#if !defined(WIFI_FEATURE) && !defined(ETH_FEATURE)
#error Hooks need at least one network defined (WIFI_FEATURE or ETH_FEATURE)
#endif //!defined(WIFI_FEATURE) && !defined(ETH_FEATURE)
#endif //#if defined(ESP_GOT_IP_HOOK) || defined(ESP_GOT_DATE_TIME_HOOK)
/**************************
* Filesystem
@ -183,4 +196,3 @@
#endif // ESP_NO_SANITY_CHECK
#endif // SANITY_ESP3D_H

View File

@ -318,7 +318,7 @@ void GcodeHost::processCommand() {
(uint8_t *)_currentCommand.c_str(), _currentCommand.length());
if (isESPcmd) {
ESP3DMessage *msg = ESP3DMessageManager::newMsg(
ESP3DClientType::stream, esp3d_commands.getOutputClient(),
ESP3DClientType::no_client, esp3d_commands.getOutputClient(),
(uint8_t *)_currentCommand.c_str(), _currentCommand.length(), _auth);
if (msg) {
// process command
@ -493,17 +493,20 @@ uint32_t GcodeHost::getCommandNumber(String &response) {
bool GcodeHost::processScript(const char *line,
ESP3DAuthenticationLevel auth_type) {
if (_step != HOST_NO_STREAM) {
esp3d_log("Streaming already in progress");
while(_step != HOST_NO_STREAM){
handle();
}
}
_script = line;
_script.trim();
esp3d_log("Processing script: %s", _script.c_str());
if (_script.length() == 0) {
esp3d_log("No script to process");
return false;
}
if (_step != HOST_NO_STREAM) {
esp3d_log("Streaming already in progress");
esp3d_log_e("No script to process");
return false;
}
_fsType = TYPE_SCRIPT_STREAM;
_step = HOST_START_STREAM;
_auth_type = auth_type;
@ -519,11 +522,11 @@ bool GcodeHost::processFile(const char *filename,
_fileName.trim();
esp3d_log("Processing file: %s", filename);
if (_fileName.length() == 0) {
esp3d_log("No file to process");
esp3d_log_e("No file to process");
return false;
}
if (_step != HOST_NO_STREAM) {
esp3d_log("Streaming already in progress");
esp3d_log_e("Streaming already in progress");
return false;
}
// TODO UD = USB DISK

View File

@ -42,7 +42,11 @@
#endif // BLUETOOTH_FEATURE
#include "../../core/esp3d_commands.h"
#include "../../core/esp3d_settings.h"
#include "../../core/esp3d_string.h"
#include "netservices.h"
#if defined(GCODE_HOST_FEATURE)
#include "../gcode_host/gcode_host.h"
#endif // GCODE_HOST_FEATURE
String NetConfig::_hostname = "";
bool NetConfig::_needReconnect2AP = false;
@ -210,10 +214,11 @@ void NetConfig::onWiFiEvent(WiFiEvent_t event) {
} break;
case WIFI_EVENT_STAMODE_GOT_IP: {
#if COMMUNICATION_PROTOCOL != MKS_SERIAL
esp3d_commands.dispatch(WiFi.localIP().toString().c_str(),
ESP3DClientType::all_clients, no_id,
ESP3DMessageType::unique, ESP3DClientType::system,
ESP3DAuthenticationLevel::admin);
#if defined (ESP_GOT_IP_HOOK) && defined (GCODE_HOST_FEATURE)
String ipMsg = esp3d_string::expandString(ESP_GOT_IP_HOOK);
esp3d_log("Got IP, sending hook: %s", ipMsg.c_str());
esp3d_gcode_host.processScript(ipMsg.c_str(), ESP3DAuthenticationLevel::admin);
#endif // #if defined (ESP_GOT_IP_HOOK) && defined (GCODE_HOST_FEATURE)
#endif // #if COMMUNICATION_PROTOCOL == MKS_SERIAL
} break;
case WIFI_EVENT_SOFTAPMODE_STACONNECTED: {
@ -251,12 +256,16 @@ void NetConfig::onWiFiEvent(WiFiEvent_t event) {
ESP3DAuthenticationLevel::admin);
EthConfig::setConnected(false);
} break;
case ARDUINO_EVENT_ETH_GOT_IP:
esp3d_commands.dispatch(ETH.localIP().toString().c_str(),
ESP3DClientType::all_clients, no_id,
ESP3DMessageType::unique, ESP3DClientType::system,
ESP3DAuthenticationLevel::admin);
case ARDUINO_EVENT_ETH_GOT_IP:{
#if COMMUNICATION_PROTOCOL != MKS_SERIAL
#if defined (ESP_GOT_IP_HOOK) && defined (GCODE_HOST_FEATURE)
String ipMsg = esp3d_string::expandString(ESP_GOT_IP_HOOK);
esp3d_log("Got IP, sending hook: %s", ipMsg.c_str());
esp3d_gcode_host.processScript(ipMsg.c_str(), ESP3DAuthenticationLevel::admin);
#endif // #if defined (ESP_GOT_IP_HOOK) && defined (GCODE_HOST_FEATURE)
#endif // #if COMMUNICATION_PROTOCOL == MKS_SERIAL
EthConfig::setConnected(true);
}
break;
case ARDUINO_EVENT_ETH_STOP:
EthConfig::setConnected(false);

View File

@ -488,6 +488,9 @@ void NetServices::handle() {
#ifdef NOTIFICATION_FEATURE
notificationsservice.handle();
#endif // NOTIFICATION_FEATURE
#if defined (TIMESTAMP_FEATURE) && (defined (ESP_GOT_IP_HOOK) || defined (ESP_GOT_DATE_TIME_HOOK))
timeService.handle();
#endif // TIMESTAMP_FEATURE
}
if (_restart) {
begin();

View File

@ -670,7 +670,7 @@ void NotificationsService::end() {
_started = false;
_notificationType = 0;
_token1 = "";
_token1 = "";
_token2 = "";
_settings = "";
_serveraddress = "";
_port = 0;

View File

@ -23,6 +23,7 @@
#include "../../core/esp3d_message.h"
#include "../../core/esp3d_settings.h"
#include "../../core/esp3d_string.h"
#include "time_service.h"
#if defined(WIFI_FEATURE)
@ -35,6 +36,10 @@
#include "../ethernet/ethconfig.h"
#endif // ETH_FEATURE
#if defined(GCODE_HOST_FEATURE)
#include "../gcode_host/gcode_host.h"
#endif // GCODE_HOST_FEATURE
TimeService timeService;
const char* SupportedTimeZones[] = {
@ -232,7 +237,25 @@ void TimeService::end() {
// currently not used
void TimeService::handle() {
static bool isSet = false;
if (_started) {
// check if time is set
time_t now = time(nullptr);
if (now < (8 * 3600 * 2)) {
esp3d_log("Time not set, retry");
isSet = false;
} else {
if (!isSet) {
esp3d_log("Time set");
isSet = true;
#if COMMUNICATION_PROTOCOL != MKS_SERIAL
#if defined(ESP_GOT_DATE_TIME_HOOK) && defined(GCODE_HOST_FEATURE)
String dateMsg = esp3d_string::expandString(ESP_GOT_DATE_TIME_HOOK, true);
esp3d_gcode_host.processScript(dateMsg.c_str());
#endif // #if defined (ESP_GOT_IP_HOOK) && defined (GCODE_HOST_FEATURE)
#endif // #if COMMUNICATION_PROTOCOL == MKS_SERIAL
}
}
}
}