| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540 |
- /**
- * esp-knx-ip library for KNX/IP communication on an ESP8266
- * Author: Nico Weichbrodt <envy>
- * License: MIT
- */
- #include "esp-knx-ip.h"
- void ESPKNXIP::__handle_root()
- {
- String m = F("<html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'>");
- #if USE_BOOTSTRAP
- m += F("<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css' integrity='sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm' crossorigin='anonymous'>");
- m += F("<style>.input-group-insert > .input-group-text { border-radius: 0; }</style>");
- #endif
- m += F("</head><body><div class='container-fluid'>");
- m += F("<h2>ESP KNX</h2>");
- // Feedback
- if (registered_feedbacks > 0)
- {
- m += F("<h4>Feedback</h4>");
- for (feedback_id_t i = 0; i < registered_feedbacks; ++i)
- {
- if (feedbacks[i].cond && !feedbacks[i].cond())
- {
- continue;
- }
- m += F("<form action='" __FEEDBACK_PATH "' method='POST'>");
- m += F("<div class='row'><div class='col-auto'><div class='input-group'>");
- m += F("<div class='input-group-prepend'><span class='input-group-text'>");
- m += feedbacks[i].name;
- m += F("</span></div>");
- switch (feedbacks[i].type)
- {
- case FEEDBACK_TYPE_INT:
- m += F("<span class='input-group-text'>");
- m += String(*(int32_t *)feedbacks[i].data);
- m += F("</span>");
- break;
- case FEEDBACK_TYPE_FLOAT:
- m += F("<span class='input-group-text'>");
- m += feedbacks[i].options.float_options.prefix;
- m += String(*(float *)feedbacks[i].data, feedbacks[i].options.float_options.precision);
- m += feedbacks[i].options.float_options.suffix;
- m += F("</span>");
- break;
- case FEEDBACK_TYPE_BOOL:
- m += F("<span class='input-group-text'>");
- m += (*(bool *)feedbacks[i].data) ? F("True") : F("False");
- m += F("</span>");
- break;
- case FEEDBACK_TYPE_ACTION:
- m += F("<input class='form-control' type='hidden' name='id' value='");
- m += i;
- m += F("' /><div class='input-group-append'><button type='submit' class='btn btn-primary'>");
- m += feedbacks[i].options.action_options.btn_text;
- m += F("</button></div>");
- break;
- }
- m += F("</div></div></div>");
- m += F("</form>");
- }
- }
- if (registered_callbacks > 0)
- m += F("<h4>Callbacks</h4>");
- if (registered_callback_assignments > 0)
- {
- for (uint8_t i = 0; i < registered_callback_assignments; ++i)
- {
- // Skip empty slots
- if ((callback_assignments[i].slot_flags & SLOT_FLAGS_USED) == 0)
- {
- continue;
- }
- // Skip disabled callbacks
- if (callbacks[callback_assignments[i].callback_id].cond && !callbacks[callback_assignments[i].callback_id].cond())
- {
- continue;
- }
- address_t &addr = callback_assignments[i].address;
- m += F("<form action='" __DELETE_PATH "' method='POST'>");
- m += F("<div class='row'><div class='col-auto'><div class='input-group'>");
- m += F("<div class='input-group-prepend'><span class='input-group-text'>");
- m += addr.ga.area;
- m += F("/");
- m += addr.ga.line;
- m += F("/");
- m += addr.ga.member;
- m += F("</span>");
- m += F("<span class='input-group-text'>");
- m += callbacks[callback_assignments[i].callback_id].name;
- m += F("</span></div>");
- m += F("<input class='form-control' type='hidden' name='id' value='");
- m += i;
- m += F("' /><div class='input-group-append'><button type='submit' class='btn btn-danger'>Delete</button></div>");
- m += F("</div></div></div>");
- m += F("</form>");
- }
- }
- if (registered_callbacks > 0)
- {
- m += F("<form action='" __REGISTER_PATH "' method='POST'>");
- m += F("<div class='row'><div class='col-auto'><div class='input-group'>");
- m += F("<input class='form-control' type='number' name='area' min='0' max='31'/>");
- m += F("<div class='input-group-insert'><span class='input-group-text'>/</span></div>");
- m += F("<input class='form-control' type='number' name='line' min='0' max='7'/>");
- m += F("<div class='input-group-insert'><span class='input-group-text'>/</span></div>");
- m += F("<input class='form-control' type='number' name='member' min='0' max='255'/>");
- m += F("<div class='input-group-insert'><span class='input-group-text'>-></span></div>");
- m += F("<select class='form-control' name='cb'>");
- for (callback_id_t i = 0; i < registered_callbacks; ++i)
- {
- // Skip empty slots
- if ((callbacks[i].slot_flags & SLOT_FLAGS_USED) == 0)
- {
- continue;
- }
- // Skip disabled callbacks
- if (callbacks[i].cond && !callbacks[i].cond())
- {
- continue;
- }
- m += F("<option value=\"");
- m += i;
- m += F("\">");
- m += callbacks[i].name;
- m += F("</option>");
- }
- m += F("</select>");
- m += F("<div class='input-group-append'><button type='submit' class='btn btn-primary'>Set</button></div>");
- m += F("</div></div></div>");
- m += F("</form>");
- }
- m += F("<h4>Configuration</h4>");
- // Physical address
- m += F("<form action='" __PHYS_PATH "' method='POST'>");
- m += F("<div class='row'><div class='col-auto'><div class='input-group'>");
- m += F("<div class='input-group-prepend'><span class='input-group-text'>Physical address</span></div>");
- m += F("<input class='form-control' type='number' name='area' min='0' max='15' value='");
- m += physaddr.pa.area;
- m += F("'/>");
- m += F("<div class='input-group-insert'><span class='input-group-text'>.</span></div>");
- m += F("<input class='form-control' type='number' name='line' min='0' max='15' value='");
- m += physaddr.pa.line;
- m += F("'/>");
- m += F("<div class='input-group-insert'><span class='input-group-text'>.</span></div>");
- m += F("<input class='form-control' type='number' name='member' min='0' max='255' value='");
- m += physaddr.pa.member;
- m += F("'/>");
- m += F("<div class='input-group-append'><button type='submit' class='btn btn-primary'>Set</button></div>");
- m += F("</div></div></div>");
- m += F("</form>");
- if (registered_configs > 0)
- {
- for (config_id_t i = 0; i < registered_configs; ++i)
- {
- // Check if this config option has a enable condition and if so check that condition
- if (custom_configs[i].cond && !custom_configs[i].cond())
- continue;
- m += F("<form action='" __CONFIG_PATH "' method='POST'>");
- m += F("<div class='row'><div class='col-auto'><div class='input-group'>");
- m += F("<div class='input-group-prepend'><span class='input-group-text'>");
- m += custom_configs[i].name;
- m += F("</span></div>");
- switch (custom_configs[i].type)
- {
- case CONFIG_TYPE_STRING:
- m += F("<input class='form-control' type='text' name='value' value='");
- m += config_get_string(i);
- m += F("' maxlength='");
- m += custom_configs[i].len - 1; // Subtract \0 byte
- m += F("'/>");
- break;
- case CONFIG_TYPE_INT:
- m += F("<input class='form-control' type='number' name='value' value='");
- m += config_get_int(i);
- m += F("'/>");
- break;
- case CONFIG_TYPE_BOOL:
- m += F("<div class='input-group-insert'><span class='input-group-text'>");
- m += F("<input type='checkbox' name='value' ");
- if (config_get_bool(i))
- m += F("checked ");
- m += F("/>");
- m += F("</span></div>");
- break;
- case CONFIG_TYPE_OPTIONS:
- {
- m += F("<select class='custom-select' name='value'>");
- option_entry_t *cur = custom_configs[i].data.options;
- while (cur->name != nullptr)
- {
- if (config_get_options(i) == cur->value)
- {
- m += F("<option selected value='");
- }
- else
- {
- m += F("<option value='");
- }
- m += cur->value;
- m += F("'>");
- m += String(cur->name);
- m += F("</option>");
- cur++;
- }
- m += F("");
- m += F("</select>");
- break;
- }
- case CONFIG_TYPE_GA:
- address_t a = config_get_ga(i);
- m += F("<input class='form-control' type='number' name='area' min='0' max='31' value='");
- m += a.ga.area;
- m += F("'/>");
- m += F("<div class='input-group-insert'><span class='input-group-text'>/</span></div>");
- m += F("<input class='form-control' type='number' name='line' min='0' max='7' value='");
- m += a.ga.line;
- m += F("'/>");
- m += F("<div class='input-group-insert'><span class='input-group-text'>/</span></div>");
- m += F("<input class='form-control' type='number' name='member' min='0' max='255' value='");
- m += a.ga.member;
- m += F("'/>");
- break;
- }
- m += F("<input type='hidden' name='id' value='");
- m += i;
- m += F("'/>");
- m += F("<div class='input-group-append'><button type='submit' class='btn btn-primary'>Set</button></div>");
- m += F("</div></div></div>");
- m += F("</form>");
- }
- }
- #if !(DISABLE_EEPROM_BUTTONS && DISABLE_RESTORE_BUTTON && DISABLE_REBOOT_BUTTON)
- // EEPROM save and restore
- m += F("<div class='row'>");
- // Save to EEPROM
- #if !DISABLE_EEPROM_BUTTONS
- m += F("<div class='col-auto'>");
- m += F("<form action='" __EEPROM_PATH "' method='POST'>");
- m += F("<input type='hidden' name='mode' value='1'>");
- m += F("<button type='submit' class='btn btn-success'>Save to EEPROM</button>");
- m += F("</form>");
- m += F("</div>");
- // Restore from EEPROM
- m += F("<div class='col-auto'>");
- m += F("<form action='" __EEPROM_PATH "' method='POST'>");
- m += F("<input type='hidden' name='mode' value='2'>");
- m += F("<button type='submit' class='btn btn-info'>Restore from EEPROM</button>");
- m += F("</form>");
- m += F("</div>");
- #endif
- #if !DISABLE_RESTORE_BUTTON
- // Load Defaults
- m += F("<div class='col-auto'>");
- m += F("<form action='" __RESTORE_PATH "' method='POST'>");
- m += F("<button type='submit' class='btn btn-warning'>Restore defaults</button>");
- m += F("</form>");
- m += F("</div>");
- #endif
- #if !DISABLE_REBOOT_BUTTON
- // Reboot
- m += F("<div class='col-auto'>");
- m += F("<form action='" __REBOOT_PATH "' method='POST'>");
- m += F("<button type='submit' class='btn btn-danger'>Reboot</button>");
- m += F("</form>");
- m += F("</div>");
- #endif
- m += F("</div>"); // row
- #endif
- // End of page
- m += F("</div></body></html>");
- server->send(200, F("text/html"), m);
- }
- void ESPKNXIP::__handle_register()
- {
- DEBUG_PRINTLN(F("Register called"));
- if (server->hasArg(F("area")) && server->hasArg(F("line")) && server->hasArg(F("member")) && server->hasArg(F("cb")))
- {
- uint8_t area = server->arg(F("area")).toInt();
- uint8_t line = server->arg(F("line")).toInt();
- uint8_t member = server->arg(F("member")).toInt();
- callback_id_t cb = (callback_id_t)server->arg(F("cb")).toInt();
- DEBUG_PRINT(F("Got args: "));
- DEBUG_PRINT(area);
- DEBUG_PRINT(F("/"));
- DEBUG_PRINT(line);
- DEBUG_PRINT(F("/"));
- DEBUG_PRINT(member);
- DEBUG_PRINT(F("/"));
- DEBUG_PRINT(cb);
- DEBUG_PRINTLN(F(""));
- if (area > 31 || line > 7)
- {
- DEBUG_PRINTLN(F("Area or Line wrong"));
- goto end;
- }
- if (!__callback_is_id_valid(cb))
- {
- DEBUG_PRINTLN(F("Invalid callback id"));
- goto end;
- }
- address_t ga = {.ga={line, area, member}};
- __callback_register_assignment(ga, cb);
- }
- end:
- server->sendHeader(F("Location"),F(__ROOT_PATH));
- server->send(302);
- }
- void ESPKNXIP::__handle_delete()
- {
- DEBUG_PRINTLN(F("Delete called"));
- if (server->hasArg(F("id")))
- {
- callback_assignment_id_t id = (callback_assignment_id_t)server->arg(F("id")).toInt();
- DEBUG_PRINT(F("Got args: "));
- DEBUG_PRINT(id);
- DEBUG_PRINTLN(F(""));
- if (id >= registered_callback_assignments || (callback_assignments[id].slot_flags & SLOT_FLAGS_USED) == 0)
- {
- DEBUG_PRINTLN(F("ID wrong"));
- goto end;
- }
- __callback_delete_assignment(id);
- }
- end:
- server->sendHeader(F("Location"),F(__ROOT_PATH));
- server->send(302);
- }
- void ESPKNXIP::__handle_set()
- {
- DEBUG_PRINTLN(F("Set called"));
- if (server->hasArg(F("area")) && server->hasArg(F("line")) && server->hasArg(F("member")))
- {
- uint8_t area = server->arg(F("area")).toInt();
- uint8_t line = server->arg(F("line")).toInt();
- uint8_t member = server->arg(F("member")).toInt();
- DEBUG_PRINT(F("Got args: "));
- DEBUG_PRINT(area);
- DEBUG_PRINT(F("."));
- DEBUG_PRINT(line);
- DEBUG_PRINT(F("."));
- DEBUG_PRINT(member);
- DEBUG_PRINTLN(F(""));
- if (area > 31 || line > 7)
- {
- DEBUG_PRINTLN(F("Area or Line wrong"));
- goto end;
- }
- physaddr.bytes.high = (area << 4) | line;
- physaddr.bytes.low = member;
- }
- end:
- server->sendHeader(F("Location"),F(__ROOT_PATH));
- server->send(302);
- }
- void ESPKNXIP::__handle_config()
- {
- DEBUG_PRINTLN(F("Config called"));
- if (server->hasArg(F("id")))
- {
- config_id_t id = server->arg(F("id")).toInt();
- DEBUG_PRINT(F("Got args: "));
- DEBUG_PRINT(id);
- DEBUG_PRINTLN(F(""));
- if (id < 0 || id >= registered_configs)
- {
- DEBUG_PRINTLN(F("ID wrong"));
- goto end;
- }
- switch (custom_configs[id].type)
- {
- case CONFIG_TYPE_STRING:
- {
- String v = server->arg(F("value"));
- if (v.length() >= custom_configs[id].len)
- goto end;
- __config_set_flags(id, CONFIG_FLAGS_VALUE_SET);
- __config_set_string(id, v);
- break;
- }
- case CONFIG_TYPE_INT:
- {
- __config_set_flags(id, CONFIG_FLAGS_VALUE_SET);
- __config_set_int(id, server->arg(F("value")).toInt());
- break;
- }
- case CONFIG_TYPE_BOOL:
- {
- __config_set_flags(id, CONFIG_FLAGS_VALUE_SET);
- __config_set_bool(id, server->arg(F("value")).compareTo(F("on")) == 0);
- break;
- }
- case CONFIG_TYPE_OPTIONS:
- {
- uint8_t val = (uint8_t)server->arg(F("value")).toInt();
- DEBUG_PRINT(F("Value: "));
- DEBUG_PRINTLN(val);
- config_set_options(id, val);
- break;
- }
- case CONFIG_TYPE_GA:
- {
- uint8_t area = server->arg(F("area")).toInt();
- uint8_t line = server->arg(F("line")).toInt();
- uint8_t member = server->arg(F("member")).toInt();
- if (area > 31 || line > 7)
- {
- DEBUG_PRINTLN(F("Area or Line wrong"));
- goto end;
- }
- address_t tmp;
- tmp.bytes.high = (area << 3) | line;
- tmp.bytes.low = member;
- __config_set_flags(id, CONFIG_FLAGS_VALUE_SET);
- __config_set_ga(id, tmp);
- break;
- }
- }
- }
- end:
- server->sendHeader(F("Location"),F(__ROOT_PATH));
- server->send(302);
- }
- void ESPKNXIP::__handle_feedback()
- {
- DEBUG_PRINTLN(F("Feedback called"));
- if (server->hasArg(F("id")))
- {
- config_id_t id = server->arg(F("id")).toInt();
- DEBUG_PRINT(F("Got args: "));
- DEBUG_PRINT(id);
- DEBUG_PRINTLN(F(""));
- if (id < 0 || id >= registered_feedbacks)
- {
- DEBUG_PRINTLN(F("ID wrong"));
- goto end;
- }
- switch (feedbacks[id].type)
- {
- case FEEDBACK_TYPE_ACTION:
- {
- feedback_action_fptr_t func = (feedback_action_fptr_t)feedbacks[id].data;
- void *arg = feedbacks[id].options.action_options.arg;
- func(arg);
- break;
- }
- default:
- DEBUG_PRINTLN(F("Feedback has no action"));
- break;
- }
- }
- end:
- server->sendHeader(F("Location"),F(__ROOT_PATH));
- server->send(302);
- }
- #if !DISABLE_RESTORE_BUTTONS
- void ESPKNXIP::__handle_restore()
- {
- DEBUG_PRINTLN(F("Restore called"));
- memcpy(custom_config_data, custom_config_default_data, MAX_CONFIG_SPACE);
- end:
- server->sendHeader(F("Location"),F(__ROOT_PATH));
- server->send(302);
- }
- #endif
- #if !DISABLE_REBOOT_BUTTONS
- void ESPKNXIP::__handle_reboot()
- {
- DEBUG_PRINTLN(F("Rebooting!"));
- server->sendHeader(F("Location"),F(__ROOT_PATH));
- server->send(302);
- delay(1000);
- ESP.restart();
- //while(1);
- }
- #endif
- #if !DISABLE_EEPROM_BUTTONS
- void ESPKNXIP::__handle_eeprom()
- {
- DEBUG_PRINTLN(F("EEPROM called"));
- if (server->hasArg(F("mode")))
- {
- uint8_t mode = server->arg(F("mode")).toInt();
- DEBUG_PRINT(F("Got args: "));
- DEBUG_PRINT(mode);
- DEBUG_PRINTLN(F(""));
- if (mode == 1)
- {
- // save
- save_to_eeprom();
- }
- else if (mode == 2)
- {
- // restore
- restore_from_eeprom();
- }
- }
- end:
- server->sendHeader(F("Location"),F(__ROOT_PATH));
- server->send(302);
- }
- #endif
|