mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-09-15 11:05:08 +00:00
923 lines
29 KiB
Arduino
923 lines
29 KiB
Arduino
#ifdef WEBSERVER_DEVICES
|
|
|
|
# include "src/Globals/Nodes.h"
|
|
# include "src/Globals/Device.h"
|
|
# include "src/Globals/CPlugins.h"
|
|
# include "src/Globals/Plugins.h"
|
|
# include "src/Static/WebStaticData.h"
|
|
|
|
|
|
void handle_devices() {
|
|
checkRAM(F("handle_devices"));
|
|
|
|
if (!isLoggedIn()) { return; }
|
|
navMenuIndex = MENU_INDEX_DEVICES;
|
|
TXBuffer.startStream();
|
|
sendHeadandTail_stdtemplate(_HEAD);
|
|
|
|
|
|
// char tmpString[41];
|
|
|
|
|
|
// String taskindex = web_server.arg(F("index"));
|
|
|
|
pluginID_t taskdevicenumber;
|
|
|
|
if (web_server.hasArg(F("del"))) {
|
|
taskdevicenumber = 0;
|
|
}
|
|
else {
|
|
taskdevicenumber = getFormItemInt(F("TDNUM"), 0);
|
|
}
|
|
|
|
|
|
// String taskdeviceid[CONTROLLER_MAX];
|
|
// String taskdevicepin1 = web_server.arg(F("taskdevicepin1")); // "taskdevicepin*" should not be changed because it is uses by plugins
|
|
// and expected to be saved by this code
|
|
// String taskdevicepin2 = web_server.arg(F("taskdevicepin2"));
|
|
// String taskdevicepin3 = web_server.arg(F("taskdevicepin3"));
|
|
// String taskdevicepin1pullup = web_server.arg(F("TDPPU"));
|
|
// String taskdevicepin1inversed = web_server.arg(F("TDPI"));
|
|
// String taskdevicename = web_server.arg(F("TDN"));
|
|
// String taskdeviceport = web_server.arg(F("TDP"));
|
|
// String taskdeviceformula[VARS_PER_TASK];
|
|
// String taskdevicevaluename[VARS_PER_TASK];
|
|
// String taskdevicevaluedecimals[VARS_PER_TASK];
|
|
// String taskdevicesenddata[CONTROLLER_MAX];
|
|
// String taskdeviceglobalsync = web_server.arg(F("TDGS"));
|
|
// String taskdeviceenabled = web_server.arg(F("TDE"));
|
|
|
|
// for (byte varNr = 0; varNr < VARS_PER_TASK; varNr++)
|
|
// {
|
|
// char argc[25];
|
|
// String arg = F("TDF");
|
|
// arg += varNr + 1;
|
|
// arg.toCharArray(argc, 25);
|
|
// taskdeviceformula[varNr] = web_server.arg(argc);
|
|
//
|
|
// arg = F("TDVN");
|
|
// arg += varNr + 1;
|
|
// arg.toCharArray(argc, 25);
|
|
// taskdevicevaluename[varNr] = web_server.arg(argc);
|
|
//
|
|
// arg = F("TDVD");
|
|
// arg += varNr + 1;
|
|
// arg.toCharArray(argc, 25);
|
|
// taskdevicevaluedecimals[varNr] = web_server.arg(argc);
|
|
// }
|
|
|
|
// for (controllerIndex_t controllerNr = 0; controllerNr < CONTROLLER_MAX; controllerNr++)
|
|
// {
|
|
// char argc[25];
|
|
// String arg = F("TDID");
|
|
// arg += controllerNr + 1;
|
|
// arg.toCharArray(argc, 25);
|
|
// taskdeviceid[controllerNr] = web_server.arg(argc);
|
|
//
|
|
// arg = F("TDSD");
|
|
// arg += controllerNr + 1;
|
|
// arg.toCharArray(argc, 25);
|
|
// taskdevicesenddata[controllerNr] = web_server.arg(argc);
|
|
// }
|
|
|
|
byte page = getFormItemInt(F("page"), 0);
|
|
|
|
if (page == 0) {
|
|
page = 1;
|
|
}
|
|
byte setpage = getFormItemInt(F("setpage"), 0);
|
|
|
|
if (setpage > 0)
|
|
{
|
|
if (setpage <= (TASKS_MAX / TASKS_PER_PAGE)) {
|
|
page = setpage;
|
|
}
|
|
else {
|
|
page = TASKS_MAX / TASKS_PER_PAGE;
|
|
}
|
|
}
|
|
const int edit = getFormItemInt(F("edit"), 0);
|
|
|
|
// taskIndex in the URL is 1 ... TASKS_MAX
|
|
// For use in other functions, set it to 0 ... (TASKS_MAX - 1)
|
|
taskIndex_t taskIndex = getFormItemInt(F("index"), 0);
|
|
boolean taskIndexNotSet = taskIndex == 0;
|
|
|
|
if (!taskIndexNotSet) {
|
|
--taskIndex;
|
|
LoadTaskSettings(taskIndex); // Make sure ExtraTaskSettings are up-to-date
|
|
}
|
|
|
|
// FIXME TD-er: Might have to clear any caches here.
|
|
if ((edit != 0) && !taskIndexNotSet) // when form submitted
|
|
{
|
|
if (Settings.TaskDeviceNumber[taskIndex] != taskdevicenumber)
|
|
{
|
|
// change of device: cleanup old device and reset default settings
|
|
setTaskDevice_to_TaskIndex(taskdevicenumber, taskIndex);
|
|
}
|
|
else if (taskdevicenumber != 0) // save settings
|
|
{
|
|
handle_devices_CopySubmittedSettings(taskIndex, taskdevicenumber);
|
|
}
|
|
|
|
if (taskdevicenumber != 0) {
|
|
// Task index has a task device number, so it makes sense to save.
|
|
// N.B. When calling delete, the settings were already saved.
|
|
addHtmlError(SaveTaskSettings(taskIndex));
|
|
addHtmlError(SaveSettings());
|
|
|
|
if (Settings.TaskDeviceEnabled[taskIndex]) {
|
|
struct EventStruct TempEvent;
|
|
TempEvent.TaskIndex = taskIndex;
|
|
String dummy;
|
|
PluginCall(PLUGIN_INIT, &TempEvent, dummy);
|
|
}
|
|
}
|
|
}
|
|
|
|
// show all tasks as table
|
|
if (taskIndexNotSet)
|
|
{
|
|
handle_devicess_ShowAllTasksTable(page);
|
|
}
|
|
|
|
// Show edit form if a specific entry is chosen with the edit button
|
|
else
|
|
{
|
|
handle_devices_TaskSettingsPage(taskIndex, page);
|
|
}
|
|
|
|
checkRAM(F("handle_devices"));
|
|
# ifndef BUILD_NO_DEBUG
|
|
|
|
if (loglevelActiveFor(LOG_LEVEL_DEBUG_DEV)) {
|
|
String log = F("DEBUG: String size:");
|
|
log += String(TXBuffer.sentBytes);
|
|
addLog(LOG_LEVEL_DEBUG_DEV, log);
|
|
}
|
|
# endif // ifndef BUILD_NO_DEBUG
|
|
sendHeadandTail_stdtemplate(_TAIL);
|
|
TXBuffer.endStream();
|
|
}
|
|
|
|
// ********************************************************************************
|
|
// Add a device select dropdown list
|
|
// TODO TD-er: Add JavaScript filter:
|
|
// https://www.w3schools.com/howto/howto_js_filter_dropdown.asp
|
|
// ********************************************************************************
|
|
void addDeviceSelect(const String& name, int choice)
|
|
{
|
|
String deviceName;
|
|
|
|
addSelector_Head_reloadOnChange(name);
|
|
addSelector_Item(F("- None -"), 0, false, false, "");
|
|
|
|
for (byte x = 0; x <= deviceCount; x++)
|
|
{
|
|
const deviceIndex_t deviceIndex = DeviceIndex_sorted[x];
|
|
|
|
if (validDeviceIndex(deviceIndex)) {
|
|
const pluginID_t pluginID = DeviceIndex_to_Plugin_id[deviceIndex];
|
|
|
|
if (validPluginID(pluginID)) {
|
|
deviceName = getPluginNameFromDeviceIndex(deviceIndex);
|
|
|
|
|
|
# ifdef PLUGIN_BUILD_DEV
|
|
String plugin = "P";
|
|
|
|
if (pluginID < 10) { plugin += '0'; }
|
|
|
|
if (pluginID < 100) { plugin += '0'; }
|
|
plugin += pluginID;
|
|
plugin += F(" - ");
|
|
deviceName = plugin + deviceName;
|
|
# endif // ifdef PLUGIN_BUILD_DEV
|
|
|
|
addSelector_Item(deviceName,
|
|
Device[deviceIndex].Number,
|
|
choice == Device[deviceIndex].Number,
|
|
false,
|
|
"");
|
|
}
|
|
}
|
|
}
|
|
addSelector_Foot();
|
|
}
|
|
|
|
// ********************************************************************************
|
|
// Collect all submitted form data and store the task settings
|
|
// ********************************************************************************
|
|
void handle_devices_CopySubmittedSettings(taskIndex_t taskIndex, pluginID_t taskdevicenumber)
|
|
{
|
|
if (!validTaskIndex(taskIndex)) { return; }
|
|
const deviceIndex_t DeviceIndex = getDeviceIndex(taskdevicenumber);
|
|
|
|
if (!validDeviceIndex(DeviceIndex)) { return; }
|
|
|
|
unsigned long taskdevicetimer = getFormItemInt(F("TDT"), 0);
|
|
Settings.TaskDeviceNumber[taskIndex] = taskdevicenumber;
|
|
|
|
|
|
int pin1 = -1;
|
|
int pin2 = -1;
|
|
int pin3 = -1;
|
|
update_whenset_FormItemInt(F("taskdevicepin1"), pin1);
|
|
update_whenset_FormItemInt(F("taskdevicepin2"), pin2);
|
|
update_whenset_FormItemInt(F("taskdevicepin3"), pin3);
|
|
setBasicTaskValues(taskIndex, taskdevicetimer,
|
|
isFormItemChecked(F("TDE")), web_server.arg(F("TDN")),
|
|
pin1, pin2, pin3);
|
|
Settings.TaskDevicePort[taskIndex] = getFormItemInt(F("TDP"), 0);
|
|
update_whenset_FormItemInt(F("remoteFeed"), Settings.TaskDeviceDataFeed[taskIndex]);
|
|
|
|
for (controllerIndex_t controllerNr = 0; controllerNr < CONTROLLER_MAX; controllerNr++)
|
|
{
|
|
Settings.TaskDeviceID[controllerNr][taskIndex] = getFormItemInt(String(F("TDID")) + (controllerNr + 1));
|
|
Settings.TaskDeviceSendData[controllerNr][taskIndex] = isFormItemChecked(String(F("TDSD")) + (controllerNr + 1));
|
|
}
|
|
|
|
if (Device[DeviceIndex].PullUpOption) {
|
|
Settings.TaskDevicePin1PullUp[taskIndex] = isFormItemChecked(F("TDPPU"));
|
|
}
|
|
|
|
if (Device[DeviceIndex].InverseLogicOption) {
|
|
Settings.TaskDevicePin1Inversed[taskIndex] = isFormItemChecked(F("TDPI"));
|
|
}
|
|
|
|
for (byte varNr = 0; varNr < Device[DeviceIndex].ValueCount; varNr++)
|
|
{
|
|
strncpy_webserver_arg(ExtraTaskSettings.TaskDeviceFormula[varNr], String(F("TDF")) + (varNr + 1));
|
|
ExtraTaskSettings.TaskDeviceValueDecimals[varNr] = getFormItemInt(String(F("TDVD")) + (varNr + 1));
|
|
strncpy_webserver_arg(ExtraTaskSettings.TaskDeviceValueNames[varNr], String(F("TDVN")) + (varNr + 1));
|
|
|
|
// taskdeviceformula[varNr].toCharArray(tmpString, 41);
|
|
// strcpy(ExtraTaskSettings.TaskDeviceFormula[varNr], tmpString);
|
|
// ExtraTaskSettings.TaskDeviceValueDecimals[varNr] = taskdevicevaluedecimals[varNr].toInt();
|
|
// taskdevicevaluename[varNr].toCharArray(tmpString, 41);
|
|
}
|
|
|
|
// // task value names handling.
|
|
// for (byte varNr = 0; varNr < Device[DeviceIndex].ValueCount; varNr++)
|
|
// {
|
|
// taskdevicevaluename[varNr].toCharArray(tmpString, 41);
|
|
// strcpy(ExtraTaskSettings.TaskDeviceValueNames[varNr], tmpString);
|
|
// }
|
|
|
|
struct EventStruct TempEvent;
|
|
TempEvent.TaskIndex = taskIndex;
|
|
|
|
if (ExtraTaskSettings.TaskIndex != TempEvent.TaskIndex) { // if field set empty, reload defaults
|
|
String dummy;
|
|
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, &TempEvent, dummy);
|
|
}
|
|
|
|
// allow the plugin to save plugin-specific form settings.
|
|
{
|
|
String dummy;
|
|
PluginCall(PLUGIN_WEBFORM_SAVE, &TempEvent, dummy);
|
|
}
|
|
|
|
// notify controllers: CPlugin::Function::CPLUGIN_TASK_CHANGE_NOTIFICATION
|
|
for (controllerIndex_t x = 0; x < CONTROLLER_MAX; x++)
|
|
{
|
|
TempEvent.ControllerIndex = x;
|
|
|
|
if (Settings.TaskDeviceSendData[TempEvent.ControllerIndex][TempEvent.TaskIndex] &&
|
|
Settings.ControllerEnabled[TempEvent.ControllerIndex] && Settings.Protocol[TempEvent.ControllerIndex])
|
|
{
|
|
protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(TempEvent.ControllerIndex);
|
|
String dummy;
|
|
CPluginCall(ProtocolIndex, CPlugin::Function::CPLUGIN_TASK_CHANGE_NOTIFICATION, &TempEvent, dummy);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ********************************************************************************
|
|
// Show table with all selected Tasks/Devices
|
|
// ********************************************************************************
|
|
void handle_devicess_ShowAllTasksTable(byte page)
|
|
{
|
|
html_add_script(true);
|
|
TXBuffer += DATA_UPDATE_SENSOR_VALUES_DEVICE_PAGE_JS;
|
|
html_add_script_end();
|
|
html_table_class_multirow();
|
|
html_TR();
|
|
html_table_header("", 70);
|
|
|
|
if (TASKS_MAX != TASKS_PER_PAGE)
|
|
{
|
|
html_add_button_prefix();
|
|
|
|
{
|
|
String html;
|
|
html.reserve(30);
|
|
|
|
html += F("devices?setpage=");
|
|
|
|
if (page > 1) {
|
|
html += page - 1;
|
|
}
|
|
else {
|
|
html += page;
|
|
}
|
|
html += F("'><</a>");
|
|
addHtml(html);
|
|
}
|
|
html_add_button_prefix();
|
|
{
|
|
String html;
|
|
html.reserve(30);
|
|
|
|
html += F("devices?setpage=");
|
|
|
|
if (page < (TASKS_MAX / TASKS_PER_PAGE)) {
|
|
html += page + 1;
|
|
}
|
|
else {
|
|
html += page;
|
|
}
|
|
html += F("'>></a>");
|
|
addHtml(html);
|
|
}
|
|
}
|
|
|
|
html_table_header("Task", 50);
|
|
html_table_header(F("Enabled"), 100);
|
|
html_table_header(F("Device"));
|
|
html_table_header("Name");
|
|
html_table_header("Port");
|
|
html_table_header(F("Ctr (IDX)"), 100);
|
|
html_table_header("GPIO", 100);
|
|
html_table_header(F("Values"));
|
|
|
|
String deviceName;
|
|
|
|
for (byte x = (page - 1) * TASKS_PER_PAGE; x < ((page) * TASKS_PER_PAGE) && validTaskIndex(x); x++)
|
|
{
|
|
const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(x);
|
|
const bool pluginID_set = INVALID_PLUGIN_ID != Settings.TaskDeviceNumber[x];
|
|
|
|
html_TR_TD();
|
|
|
|
if (pluginID_set && !supportedPluginID(Settings.TaskDeviceNumber[x])) {
|
|
html_add_button_prefix(F("red"), true);
|
|
} else {
|
|
html_add_button_prefix();
|
|
}
|
|
{
|
|
String html;
|
|
html.reserve(30);
|
|
|
|
html += F("devices?index=");
|
|
html += x + 1;
|
|
html += F("&page=");
|
|
html += page;
|
|
html += F("'>");
|
|
|
|
if (pluginID_set) {
|
|
html += F("Edit");
|
|
} else {
|
|
html += F("Add");
|
|
}
|
|
html += F("</a><TD>");
|
|
html += x + 1;
|
|
addHtml(html);
|
|
html_TD();
|
|
}
|
|
|
|
// Show table of all configured tasks
|
|
// A task may also refer to a non supported plugin.
|
|
// This will be shown as not supported.
|
|
// Editing a task which has a non supported plugin will present the same as when assigning a new plugin to a task.
|
|
if (pluginID_set)
|
|
{
|
|
LoadTaskSettings(x);
|
|
struct EventStruct TempEvent;
|
|
TempEvent.TaskIndex = x;
|
|
addEnabled(Settings.TaskDeviceEnabled[x] && validDeviceIndex(DeviceIndex));
|
|
|
|
html_TD();
|
|
addHtml(getPluginNameFromPluginID(Settings.TaskDeviceNumber[x]));
|
|
html_TD();
|
|
addHtml(ExtraTaskSettings.TaskDeviceName);
|
|
html_TD();
|
|
|
|
if (validDeviceIndex(DeviceIndex)) {
|
|
if (Settings.TaskDeviceDataFeed[x] != 0) {
|
|
// Show originating node number
|
|
byte remoteUnit = Settings.TaskDeviceDataFeed[x];
|
|
addHtml(F("Unit "));
|
|
addHtml(String(remoteUnit));
|
|
|
|
if (remoteUnit != 255) {
|
|
NodesMap::iterator it = Nodes.find(remoteUnit);
|
|
|
|
if (it != Nodes.end()) {
|
|
addHtml(F(" - "));
|
|
addHtml(it->second.nodeName);
|
|
} else {
|
|
addHtml(F(" - Not Seen recently"));
|
|
}
|
|
}
|
|
} else {
|
|
String portDescr;
|
|
|
|
if (PluginCall(PLUGIN_WEBFORM_SHOW_CONFIG, &TempEvent, portDescr)) {
|
|
addHtml(portDescr);
|
|
} else {
|
|
switch (Device[DeviceIndex].Type) {
|
|
case DEVICE_TYPE_I2C:
|
|
addHtml(F("I2C"));
|
|
break;
|
|
case DEVICE_TYPE_SERIAL:
|
|
case DEVICE_TYPE_SERIAL_PLUS1:
|
|
addHtml(serialHelper_getSerialTypeLabel(&TempEvent));
|
|
break;
|
|
|
|
default:
|
|
|
|
// Plugin has no custom port formatting, show default one.
|
|
if (Device[DeviceIndex].Ports != 0)
|
|
{
|
|
addHtml(formatToHex_decimal(Settings.TaskDevicePort[x]));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
html_TD();
|
|
|
|
if (validDeviceIndex(DeviceIndex)) {
|
|
if (Device[DeviceIndex].SendDataOption)
|
|
{
|
|
boolean doBR = false;
|
|
|
|
for (controllerIndex_t controllerNr = 0; controllerNr < CONTROLLER_MAX; controllerNr++)
|
|
{
|
|
if (Settings.TaskDeviceSendData[controllerNr][x])
|
|
{
|
|
if (doBR) {
|
|
html_BR();
|
|
}
|
|
addHtml(getControllerSymbol(controllerNr));
|
|
protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerNr);
|
|
|
|
if (validProtocolIndex(ProtocolIndex)) {
|
|
if (Protocol[ProtocolIndex].usesID && (Settings.Protocol[controllerNr] != 0))
|
|
{
|
|
String html;
|
|
html.reserve(16);
|
|
html += " (";
|
|
html += Settings.TaskDeviceID[controllerNr][x];
|
|
html += ')';
|
|
|
|
if (Settings.TaskDeviceID[controllerNr][x] == 0) {
|
|
html += " ";
|
|
html += F(HTML_SYMBOL_WARNING);
|
|
}
|
|
addHtml(html);
|
|
}
|
|
doBR = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
html_TD();
|
|
|
|
if (validDeviceIndex(DeviceIndex)) {
|
|
if (Settings.TaskDeviceDataFeed[x] == 0)
|
|
{
|
|
bool showpin1 = false;
|
|
bool showpin2 = false;
|
|
bool showpin3 = false;
|
|
switch (Device[DeviceIndex].Type) {
|
|
case DEVICE_TYPE_I2C:
|
|
{
|
|
String html;
|
|
html.reserve(20);
|
|
html += F("SDA: ");
|
|
html += Settings.Pin_i2c_sda;
|
|
html += F("<BR>SCL: ");
|
|
html += Settings.Pin_i2c_scl;
|
|
|
|
addHtml(html);
|
|
break;
|
|
}
|
|
case DEVICE_TYPE_ANALOG:
|
|
{
|
|
#ifdef ESP8266
|
|
#if FEATURE_ADC_VCC
|
|
addHtml(F("ADC (VDD)"));
|
|
#else
|
|
addHtml(F("ADC (TOUT)"));
|
|
#endif
|
|
#endif
|
|
#ifdef ESP32
|
|
showpin1 = true;
|
|
addHtml(formatGpioName_ADC(Settings.TaskDevicePin1[x]));
|
|
html_BR();
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
case DEVICE_TYPE_SERIAL_PLUS1:
|
|
showpin3 = true;
|
|
// fallthrough
|
|
case DEVICE_TYPE_SERIAL:
|
|
{
|
|
addHtml(serialHelper_getGpioDescription(Settings.TaskDevicePin1[x], Settings.TaskDevicePin2[x], F("<BR>")));
|
|
if (showpin3) {
|
|
html_BR();
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
showpin1 = true;
|
|
showpin2 = true;
|
|
showpin3 = true;
|
|
break;
|
|
}
|
|
|
|
if (Settings.TaskDevicePin1[x] != -1 && showpin1)
|
|
{
|
|
String html;
|
|
html += F("GPIO-");
|
|
html += Settings.TaskDevicePin1[x];
|
|
addHtml(html);
|
|
}
|
|
|
|
if (Settings.TaskDevicePin2[x] != -1 && showpin2)
|
|
{
|
|
String html;
|
|
html += F("<BR>GPIO-");
|
|
html += Settings.TaskDevicePin2[x];
|
|
addHtml(html);
|
|
}
|
|
|
|
if (Settings.TaskDevicePin3[x] != -1 && showpin3)
|
|
{
|
|
String html;
|
|
html += F("<BR>GPIO-");
|
|
html += Settings.TaskDevicePin3[x];
|
|
addHtml(html);
|
|
}
|
|
}
|
|
}
|
|
|
|
html_TD();
|
|
|
|
if (validDeviceIndex(DeviceIndex)) {
|
|
byte customValues = false;
|
|
String customValuesString;
|
|
customValues = PluginCall(PLUGIN_WEBFORM_SHOW_VALUES, &TempEvent, customValuesString);
|
|
|
|
if (!customValues)
|
|
{
|
|
for (byte varNr = 0; varNr < Device[DeviceIndex].ValueCount; varNr++)
|
|
{
|
|
if (validPluginID_fullcheck(Settings.TaskDeviceNumber[x]))
|
|
{
|
|
addHtml(pluginWebformShowValue(x, varNr, ExtraTaskSettings.TaskDeviceValueNames[varNr], formatUserVarNoCheck(x, varNr)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
html_TD(6);
|
|
}
|
|
} // next
|
|
html_end_table();
|
|
html_end_form();
|
|
}
|
|
|
|
// ********************************************************************************
|
|
// Show the task settings page
|
|
// ********************************************************************************
|
|
void handle_devices_TaskSettingsPage(taskIndex_t taskIndex, byte page)
|
|
{
|
|
if (!validTaskIndex(taskIndex)) { return; }
|
|
const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(taskIndex);
|
|
|
|
LoadTaskSettings(taskIndex);
|
|
struct EventStruct TempEvent;
|
|
TempEvent.TaskIndex = taskIndex;
|
|
|
|
html_add_form();
|
|
html_table_class_normal();
|
|
addFormHeader(F("Task Settings"));
|
|
|
|
|
|
addHtml(F("<TR><TD style='width:150px;' align='left'>Device:<TD>"));
|
|
|
|
// no (supported) device selected, this effectively checks for validDeviceIndex
|
|
if (!supportedPluginID(Settings.TaskDeviceNumber[taskIndex]))
|
|
{
|
|
// takes lots of memory/time so call this only when needed.
|
|
addDeviceSelect("TDNUM", Settings.TaskDeviceNumber[taskIndex]); // ="taskdevicenumber"
|
|
}
|
|
|
|
// device selected
|
|
else
|
|
{
|
|
// remember selected device number
|
|
addHtml(F("<input type='hidden' name='TDNUM' value='"));
|
|
{
|
|
String html;
|
|
html += Settings.TaskDeviceNumber[taskIndex];
|
|
html += "'>";
|
|
addHtml(html);
|
|
}
|
|
|
|
// show selected device name and delete button
|
|
addHtml(getPluginNameFromDeviceIndex(DeviceIndex));
|
|
|
|
addHelpButton(String(F("Plugin")) + Settings.TaskDeviceNumber[taskIndex]);
|
|
addRTDPluginButton(Settings.TaskDeviceNumber[taskIndex]);
|
|
|
|
|
|
if ((Device[DeviceIndex].Number == 3) && (taskIndex >= 4)) // Number == 3 = PulseCounter Plugin
|
|
{
|
|
addFormNote(F("This plugin is only supported on task 1-4 for now"));
|
|
}
|
|
|
|
addFormTextBox(F("Name"), F("TDN"), ExtraTaskSettings.TaskDeviceName, NAME_FORMULA_LENGTH_MAX); // ="taskdevicename"
|
|
|
|
addFormCheckBox(F("Enabled"), F("TDE"), Settings.TaskDeviceEnabled[taskIndex]); // ="taskdeviceenabled"
|
|
|
|
// section: Sensor / Actuator
|
|
if (!Device[DeviceIndex].Custom && (Settings.TaskDeviceDataFeed[taskIndex] == 0) &&
|
|
((Device[DeviceIndex].Ports != 0) ||
|
|
(Device[DeviceIndex].PullUpOption) ||
|
|
(Device[DeviceIndex].InverseLogicOption) ||
|
|
(Device[DeviceIndex].connectedToGPIOpins())))
|
|
{
|
|
addFormSubHeader((Device[DeviceIndex].SendDataOption) ? F("Sensor") : F("Actuator"));
|
|
|
|
if (Device[DeviceIndex].Ports != 0) {
|
|
addFormNumericBox(F("Port"), F("TDP"), Settings.TaskDevicePort[taskIndex]); // ="taskdeviceport"
|
|
}
|
|
|
|
if (Device[DeviceIndex].PullUpOption)
|
|
{
|
|
addFormCheckBox(F("Internal PullUp"), F("TDPPU"), Settings.TaskDevicePin1PullUp[taskIndex]); // ="taskdevicepin1pullup"
|
|
# if defined(ESP8266)
|
|
|
|
if ((Settings.TaskDevicePin1[taskIndex] == 16) || (Settings.TaskDevicePin2[taskIndex] == 16) ||
|
|
(Settings.TaskDevicePin3[taskIndex] == 16)) {
|
|
addFormNote(F("PullDown for GPIO-16 (D0)"));
|
|
}
|
|
# endif // if defined(ESP8266)
|
|
}
|
|
|
|
if (Device[DeviceIndex].InverseLogicOption)
|
|
{
|
|
addFormCheckBox(F("Inversed Logic"), F("TDPI"), Settings.TaskDevicePin1Inversed[taskIndex]); // ="taskdevicepin1inversed"
|
|
addFormNote(F("Will go into effect on next input change."));
|
|
}
|
|
|
|
// get descriptive GPIO-names from plugin
|
|
TempEvent.String1 = F("1st GPIO");
|
|
TempEvent.String2 = F("2nd GPIO");
|
|
TempEvent.String3 = F("3rd GPIO");
|
|
String dummy;
|
|
PluginCall(PLUGIN_GET_DEVICEGPIONAMES, &TempEvent, dummy);
|
|
|
|
if (Device[DeviceIndex].connectedToGPIOpins()) {
|
|
if (Device[DeviceIndex].usesTaskDevicePin(1)) {
|
|
addFormPinSelect(TempEvent.String1, F("taskdevicepin1"), Settings.TaskDevicePin1[taskIndex]);
|
|
}
|
|
|
|
if (Device[DeviceIndex].usesTaskDevicePin(2)) {
|
|
addFormPinSelect(TempEvent.String2, F("taskdevicepin2"), Settings.TaskDevicePin2[taskIndex]);
|
|
}
|
|
|
|
if (Device[DeviceIndex].usesTaskDevicePin(3)) {
|
|
addFormPinSelect(TempEvent.String3, F("taskdevicepin3"), Settings.TaskDevicePin3[taskIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// add plugins content
|
|
if (Settings.TaskDeviceDataFeed[taskIndex] == 0) { // only show additional config for local connected sensors
|
|
String webformLoadString;
|
|
PluginCall(PLUGIN_WEBFORM_LOAD, &TempEvent, webformLoadString);
|
|
|
|
if (webformLoadString.length() > 0) {
|
|
String errorMessage;
|
|
PluginCall(PLUGIN_GET_DEVICENAME, &TempEvent, errorMessage);
|
|
errorMessage += F(": Bug in PLUGIN_WEBFORM_LOAD, should not append to string, use addHtml() instead");
|
|
addHtmlError(errorMessage);
|
|
}
|
|
}
|
|
else {
|
|
// Show remote feed information.
|
|
addFormSubHeader(F("Data Source"));
|
|
byte remoteUnit = Settings.TaskDeviceDataFeed[taskIndex];
|
|
addFormNumericBox(F("Remote Unit"), F("RemoteUnit"), remoteUnit, 0, 255);
|
|
|
|
if (remoteUnit != 255) {
|
|
NodesMap::iterator it = Nodes.find(remoteUnit);
|
|
|
|
if (it != Nodes.end()) {
|
|
addUnit(it->second.nodeName);
|
|
} else {
|
|
addUnit(F("Unknown Unit Name"));
|
|
}
|
|
}
|
|
addFormNote(F("0 = disable remote feed, 255 = broadcast")); // FIXME TD-er: Must verify if broadcast can be set.
|
|
}
|
|
|
|
|
|
// section: Data Acquisition
|
|
if (Device[DeviceIndex].SendDataOption)
|
|
{
|
|
addFormSubHeader(F("Data Acquisition"));
|
|
|
|
for (controllerIndex_t controllerNr = 0; controllerNr < CONTROLLER_MAX; controllerNr++)
|
|
{
|
|
if (Settings.Protocol[controllerNr] != 0)
|
|
{
|
|
String id = F("TDSD"); // ="taskdevicesenddata"
|
|
id += controllerNr + 1;
|
|
|
|
html_TR_TD();
|
|
addHtml(F("Send to Controller "));
|
|
addHtml(getControllerSymbol(controllerNr));
|
|
html_TD();
|
|
addCheckBox(id, Settings.TaskDeviceSendData[controllerNr][taskIndex]);
|
|
|
|
protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerNr);
|
|
|
|
if (validProtocolIndex(ProtocolIndex)) {
|
|
if (Protocol[ProtocolIndex].usesID && (Settings.Protocol[controllerNr] != 0))
|
|
{
|
|
addRowLabel(F("IDX"));
|
|
id = F("TDID"); // ="taskdeviceid"
|
|
id += controllerNr + 1;
|
|
addNumericBox(id, Settings.TaskDeviceID[controllerNr][taskIndex], 0, DOMOTICZ_MAX_IDX);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
addFormSeparator(2);
|
|
|
|
if (Device[DeviceIndex].TimerOption)
|
|
{
|
|
// FIXME: shoudn't the max be ULONG_MAX because Settings.TaskDeviceTimer is an unsigned long? addFormNumericBox only supports ints
|
|
// for min and max specification
|
|
addFormNumericBox(F("Interval"), F("TDT"), Settings.TaskDeviceTimer[taskIndex], 0, 65535); // ="taskdevicetimer"
|
|
addUnit(F("sec"));
|
|
|
|
if (Device[DeviceIndex].TimerOptional) {
|
|
addHtml(F(" (Optional for this Device)"));
|
|
}
|
|
}
|
|
|
|
// section: Values
|
|
if (!Device[DeviceIndex].Custom && (Device[DeviceIndex].ValueCount > 0))
|
|
{
|
|
addFormSubHeader(F("Values"));
|
|
html_end_table();
|
|
html_table_class_normal();
|
|
|
|
// table header
|
|
addHtml(F("<TR><TH style='width:30px;' align='center'>#"));
|
|
html_table_header("Name");
|
|
|
|
if (Device[DeviceIndex].FormulaOption)
|
|
{
|
|
html_table_header(F("Formula"), F("EasyFormula"), 0);
|
|
}
|
|
|
|
if (Device[DeviceIndex].FormulaOption || Device[DeviceIndex].DecimalsOnly)
|
|
{
|
|
html_table_header(F("Decimals"), 30);
|
|
}
|
|
|
|
// table body
|
|
for (byte varNr = 0; varNr < Device[DeviceIndex].ValueCount; varNr++)
|
|
{
|
|
html_TR_TD();
|
|
addHtml(String(varNr + 1));
|
|
html_TD();
|
|
String id = F("TDVN"); // ="taskdevicevaluename"
|
|
id += (varNr + 1);
|
|
addTextBox(id, ExtraTaskSettings.TaskDeviceValueNames[varNr], NAME_FORMULA_LENGTH_MAX);
|
|
|
|
if (Device[DeviceIndex].FormulaOption)
|
|
{
|
|
html_TD();
|
|
String id = F("TDF"); // ="taskdeviceformula"
|
|
id += (varNr + 1);
|
|
addTextBox(id, ExtraTaskSettings.TaskDeviceFormula[varNr], NAME_FORMULA_LENGTH_MAX);
|
|
}
|
|
|
|
if (Device[DeviceIndex].FormulaOption || Device[DeviceIndex].DecimalsOnly)
|
|
{
|
|
html_TD();
|
|
String id = F("TDVD"); // ="taskdevicevaluedecimals"
|
|
id += (varNr + 1);
|
|
addNumericBox(id, ExtraTaskSettings.TaskDeviceValueDecimals[varNr], 0, 6);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
addFormSeparator(4);
|
|
|
|
html_TR_TD();
|
|
addHtml(F("<TD colspan='3'>"));
|
|
html_add_button_prefix();
|
|
{
|
|
String html;
|
|
html.reserve(32);
|
|
|
|
html += F("devices?setpage=");
|
|
html += page;
|
|
html += F("'>Close</a>");
|
|
addHtml(html);
|
|
}
|
|
addSubmitButton();
|
|
addHtml(F("<input type='hidden' name='edit' value='1'>"));
|
|
addHtml(F("<input type='hidden' name='page' value='1'>"));
|
|
|
|
// if user selected a device, add the delete button
|
|
if (validPluginID_fullcheck(Settings.TaskDeviceNumber[taskIndex])) {
|
|
addSubmitButton(F("Delete"), F("del"));
|
|
}
|
|
|
|
html_end_table();
|
|
html_end_form();
|
|
}
|
|
|
|
#endif // ifdef WEBSERVER_DEVICES
|
|
|
|
|
|
// ********************************************************************************
|
|
// change of device: cleanup old device and reset default settings
|
|
// ********************************************************************************
|
|
void setTaskDevice_to_TaskIndex(pluginID_t taskdevicenumber, taskIndex_t taskIndex) {
|
|
struct EventStruct TempEvent;
|
|
|
|
TempEvent.TaskIndex = taskIndex;
|
|
String dummy;
|
|
|
|
// let the plugin do its cleanup by calling PLUGIN_EXIT with this TaskIndex
|
|
PluginCall(PLUGIN_EXIT, &TempEvent, dummy);
|
|
taskClear(taskIndex, false); // clear settings, but do not save
|
|
ClearCustomTaskSettings(taskIndex);
|
|
|
|
Settings.TaskDeviceNumber[taskIndex] = taskdevicenumber;
|
|
|
|
if (validPluginID_fullcheck(taskdevicenumber)) // set default values if a new device has been selected
|
|
{
|
|
// NOTE: do not enable task by default. allow user to enter sensible valus first and let him enable it when ready.
|
|
PluginCall(PLUGIN_SET_DEFAULTS, &TempEvent, dummy);
|
|
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, &TempEvent, dummy); // the plugin should populate ExtraTaskSettings with its default values.
|
|
} else {
|
|
// New task is empty task, thus save config now.
|
|
taskClear(taskIndex, true); // clear settings, and save
|
|
}
|
|
}
|
|
|
|
// ********************************************************************************
|
|
// Initialize task with some default values applicable for almost all tasks
|
|
// ********************************************************************************
|
|
void setBasicTaskValues(taskIndex_t taskIndex, unsigned long taskdevicetimer,
|
|
bool enabled, const String& name, int pin1, int pin2, int pin3) {
|
|
if (!validTaskIndex(taskIndex)) { return; }
|
|
const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(taskIndex);
|
|
|
|
if (!validDeviceIndex(DeviceIndex)) { return; }
|
|
|
|
LoadTaskSettings(taskIndex); // Make sure ExtraTaskSettings are up-to-date
|
|
|
|
if (taskdevicetimer > 0) {
|
|
Settings.TaskDeviceTimer[taskIndex] = taskdevicetimer;
|
|
} else {
|
|
if (!Device[DeviceIndex].TimerOptional) { // Set default delay, unless it's optional...
|
|
Settings.TaskDeviceTimer[taskIndex] = Settings.Delay;
|
|
}
|
|
else {
|
|
Settings.TaskDeviceTimer[taskIndex] = 0;
|
|
}
|
|
}
|
|
Settings.TaskDeviceEnabled[taskIndex] = enabled;
|
|
safe_strncpy(ExtraTaskSettings.TaskDeviceName, name.c_str(), sizeof(ExtraTaskSettings.TaskDeviceName));
|
|
|
|
// FIXME TD-er: Check for valid GPIO pin (and -1 for "not set")
|
|
Settings.TaskDevicePin1[taskIndex] = pin1;
|
|
Settings.TaskDevicePin2[taskIndex] = pin2;
|
|
Settings.TaskDevicePin3[taskIndex] = pin3;
|
|
SaveTaskSettings(taskIndex);
|
|
}
|