Add command UfsRun

This commit is contained in:
Theo Arends 2021-02-16 12:19:40 +01:00
parent e54487fd24
commit e16ba61dea
5 changed files with 73 additions and 41 deletions

View File

@ -10,7 +10,7 @@ All notable changes to this project will be documented in this file.
- Support for Frysk language translations by Christiaan Heerze
- ESP8266 Fallback to ``*.bin.gz`` binary when OTA upload of ``*.bin`` binary fails
- Berry language improved Tasmota integration
- Filesystem commands ``Ufs``, ``UfsType``, ``UfsSize``, ``UfsFree``, ``UfsDelete`` and ``UfsRename``
- Filesystem commands ``Ufs``, ``UfsType``, ``UfsSize``, ``UfsFree``, ``UfsDelete``, ``UfsRename`` and ``UfsRun``
- Basic support for filesystem ``autoexec.bat``
### Changed

View File

@ -95,7 +95,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
- Commands ``ZbNameKey``, ``ZbDeviceTopic``, ``ZbNoPrefix``, ``ZbEndpointSuffix``, ``ZbNoAutoBind`` and ``ZbNameTopic`` as synonyms for ``SetOption83, 89, 100, 101, 110`` and ``112``
- Commands ``ZbNoAutoBind``, ``ZbReceivedTopic`` and ``ZbOmitDevice`` as synonyms for ``SetOption116, 118`` and ``119``
- Commands ``BuzzerActive`` and ``BuzzerPwm`` as synonyms for ``SetOption67`` and ``111``
- Filesystem commands ``Ufs``, ``UfsType``, ``UfsSize``, ``UfsFree``, ``UfsDelete`` and ``UfsRename``
- Filesystem commands ``Ufs``, ``UfsType``, ``UfsSize``, ``UfsFree``, ``UfsDelete``, ``UfsRename`` and ``UfsRun``
- Basic support for filesystem ``autoexec.bat``
- Milliseconds to console output [#10152](https://github.com/arendst/Tasmota/issues/10152)
- Gpio ``Option_a1`` enabling PWM2 high impedance if powered off as used by Wyze bulbs [#10196](https://github.com/arendst/Tasmota/issues/10196)

View File

@ -370,10 +370,10 @@ enum DevGroupShareItem { DGR_SHARE_POWER = 1, DGR_SHARE_LIGHT_BRI = 2, DGR_SHARE
enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER,
SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER,
SRC_THERMOSTAT, SRC_CHAT, SRC_TCL, SRC_BERRY, SRC_AUTOEXEC, SRC_MAX };
SRC_THERMOSTAT, SRC_CHAT, SRC_TCL, SRC_BERRY, SRC_FILE, SRC_MAX };
const char kCommandSource[] PROGMEM = "I|MQTT|Restart|Button|Switch|Backlog|Serial|WebGui|WebCommand|WebConsole|PulseTimer|"
"Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|"
"Thermostat|Chat|TCL|Berry|Autoexec";
"Thermostat|Chat|TCL|Berry|File";
const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };

View File

@ -426,6 +426,9 @@ void Scheduler(void) {
DeviceGroupsLoop();
#endif // USE_DEVICE_GROUPS
BacklogLoop();
#ifdef USE_UFILESYS
FileRunLoop();
#endif // USE_UFILESYS
static uint32_t state_50msecond = 0; // State 50msecond timer
if (TimeReached(state_50msecond)) {

View File

@ -85,8 +85,10 @@ uint8_t ufs_type;
uint8_t ffs_type;
struct {
char run_file[48];
int run_file_pos = -1;
bool run_file_mutex = 0;
bool download_busy;
bool autoexec = false;
} UfsData;
/*********************************************************************************************/
@ -127,8 +129,9 @@ void UfsInitOnce(void) {
dfsp = ffsp;
}
// actually this inits flash file only
// Called from tasmota.ino at restart. This inits flash file only
void UfsInit(void) {
UfsData.run_file_pos = -1;
UfsInitOnce();
if (ufs_type) {
AddLog(LOG_LEVEL_INFO, PSTR("UFS: FlashFS mounted with %d kB free"), UfsInfo(1, 0));
@ -350,20 +353,30 @@ bool TfsRenameFile(const char *fname1, const char *fname2) {
* Autoexec support
\*********************************************************************************************/
void UfsAutoexec(void) {
void FileRunLoop(void) {
if (UfsData.run_file_pos < 0) { return; }
if (!ffs_type) { return; }
File file = ffsp->open(TASM_FILE_AUTOEXEC, "r");
if (strlen(UfsData.run_file) && !UfsData.run_file_mutex) {
File file = ffsp->open(UfsData.run_file, "r");
if (!file) { return; }
if (!file.seek(UfsData.run_file_pos)) { return; }
UfsData.run_file_mutex = true;
char cmd_line[512];
cmd_line[0] = '\0'; // Clear in case of re-entry
while (file.available()) {
uint16_t index = 0;
while (file.available()) {
uint8_t buf[1];
file.read(buf, 1);
if ((buf[0] == '\n') || (buf[0] == '\r')) {
// Line terminated with linefeed or carriage return
break;
break; // Line terminated with linefeed or carriage return
}
else if (index && (buf[0] == ';')) {
break; // End of multi command line
}
else if ((0 == index) && isspace(buf[0])) {
// Skip leading spaces (' ','\t','\n','\v','\f','\r')
@ -374,13 +387,25 @@ void UfsAutoexec(void) {
}
if ((index > 0) && (index < sizeof(cmd_line) - 1) && (cmd_line[0] != ';')) {
// No comment so try to execute command
cmd_line[index] = 0;
ExecuteCommand(cmd_line, SRC_AUTOEXEC);
cmd_line[index] = '\0';
break;
}
delay(0);
}
UfsData.run_file_pos = (file.available()) ? file.position() : -1;
file.close();
if (strlen(cmd_line)) {
ExecuteCommand(cmd_line, SRC_FILE);
}
file.close();
UfsData.run_file_mutex = false;
}
}
void UfsAutoexec(void) {
if (TfsFileExists(TASM_FILE_AUTOEXEC)) {
snprintf(UfsData.run_file, sizeof(UfsData.run_file), TASM_FILE_AUTOEXEC);
UfsData.run_file_pos = 0;
}
}
/*********************************************************************************************\
@ -388,10 +413,10 @@ void UfsAutoexec(void) {
\*********************************************************************************************/
const char kUFSCommands[] PROGMEM = "Ufs|" // Prefix
"|Type|Size|Free|Delete|Rename";
"|Type|Size|Free|Delete|Rename|Run";
void (* const kUFSCommand[])(void) PROGMEM = {
&UFSInfo, &UFSType, &UFSSize, &UFSFree, &UFSDelete, &UFSRename};
&UFSInfo, &UFSType, &UFSSize, &UFSFree, &UFSDelete, &UFSRename, &UFSRun};
void UFSInfo(void) {
Response_P(PSTR("{\"Ufs\":{\"Type\":%d,\"Size\":%d,\"Free\":%d}"), ufs_type, UfsInfo(0, 0), UfsInfo(1, 0));
@ -465,6 +490,18 @@ void UFSRename(void) {
}
}
void UFSRun(void) {
if (XdrvMailbox.data_len > 0) {
if ((UfsData.run_file_pos < 0) && TfsFileExists(XdrvMailbox.data)) {
snprintf(UfsData.run_file, sizeof(UfsData.run_file), XdrvMailbox.data);
UfsData.run_file_pos = 0;
ResponseClear();
} else {
ResponseCmndChar(PSTR(D_JSON_FAILED));
}
}
}
/*********************************************************************************************\
* Web support
\*********************************************************************************************/
@ -824,16 +861,8 @@ bool Xdrv50(uint8_t function) {
UfsCheckSDCardInit();
break;
#endif // USE_SDCARD
case FUNC_EVERY_SECOND:
if (UfsData.autoexec) {
// Safe to execute autoexec commands here
UfsData.autoexec = false;
if (!TasmotaGlobal.no_autoexec) { UfsAutoexec(); }
}
break;
case FUNC_MQTT_INIT:
// Do not execute autoexec commands here
UfsData.autoexec = true;
if (!TasmotaGlobal.no_autoexec) { UfsAutoexec(); }
break;
case FUNC_COMMAND:
result = DecodeCommand(kUFSCommands, kUFSCommand);