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 - Support for Frysk language translations by Christiaan Heerze
- ESP8266 Fallback to ``*.bin.gz`` binary when OTA upload of ``*.bin`` binary fails - ESP8266 Fallback to ``*.bin.gz`` binary when OTA upload of ``*.bin`` binary fails
- Berry language improved Tasmota integration - 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`` - Basic support for filesystem ``autoexec.bat``
### Changed ### 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 ``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 ``ZbNoAutoBind``, ``ZbReceivedTopic`` and ``ZbOmitDevice`` as synonyms for ``SetOption116, 118`` and ``119``
- Commands ``BuzzerActive`` and ``BuzzerPwm`` as synonyms for ``SetOption67`` and ``111`` - 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`` - Basic support for filesystem ``autoexec.bat``
- Milliseconds to console output [#10152](https://github.com/arendst/Tasmota/issues/10152) - 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) - 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, 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_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|" 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|" "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 }; 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(); DeviceGroupsLoop();
#endif // USE_DEVICE_GROUPS #endif // USE_DEVICE_GROUPS
BacklogLoop(); BacklogLoop();
#ifdef USE_UFILESYS
FileRunLoop();
#endif // USE_UFILESYS
static uint32_t state_50msecond = 0; // State 50msecond timer static uint32_t state_50msecond = 0; // State 50msecond timer
if (TimeReached(state_50msecond)) { if (TimeReached(state_50msecond)) {

View File

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