diff --git a/sonoff/xdrv_10_KNX.ino b/sonoff/xdrv_10_KNX.ino index 1301e1d2d..171a511ca 100644 --- a/sonoff/xdrv_10_KNX.ino +++ b/sonoff/xdrv_10_KNX.ino @@ -22,11 +22,14 @@ #include // Include ESP KNX IP library (https://github.com/envy/esp-knx-ip) // use the async-udp branch (https://github.com/envy/esp-knx-ip/tree/async-udp) - // change on esp-knx-ip.h file the following: - // #define ALLOW_MULTIPLE_CALLBACKS_PER_ADDRESS 1 - // //#define ESP_KNX_DEBUG <-- comment this line + // use the library patched with https://github.com/envy/esp-knx-ip/pull/48 + // and with https://github.com/envy/esp-knx-ip/pull/52 // The ESP KNX IP library calls ESPAsyncUDP library (https://github.com/me-no-dev/ESPAsyncUDP) // use ESPAsyncUDP library patched with the PR #21 (https://github.com/me-no-dev/ESPAsyncUDP/pull/21) + // + // A copy of both libraries with the modifications needed is available at: + // https://github.com/ascillato/Sonoff-Tasmota_KNX/tree/development/lib/esp-knx-ip-async-udp + // https://github.com/ascillato/Sonoff-Tasmota_KNX/tree/development/lib/ESPAsyncUDP-master /* Variables in settings.h @@ -175,6 +178,74 @@ byte KNX_GA_Search( byte param, byte start = 0 ) } +void KNX_ADD_GA( byte GAop, byte GA_FNUM, byte GA_AREA, byte GA_FDEF ) +{ + //Check if all GA were assigned. If yes-> return + //assign a GA to that address + + + + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "ADD GA: %d, to %d/%d/%d"), + GAop, GA_FNUM, GA_AREA, GA_FDEF ); + AddLog(LOG_LEVEL_INFO); + +} + + +void KNX_DEL_GA( byte GAnum ) +{ + + + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "DEL GA %d"), + GAnum ); + AddLog(LOG_LEVEL_INFO); +} + + +void KNX_ADD_CB( byte CBop, byte CB_FNUM, byte CB_AREA, byte CB_FDEF ) +{ + //Check if all callbacks were assigned. If yes-> return + //check if a CB for CBop was registered on the ESP-KNX-IP Library + //if no, register the CB for CBop + //assign a callback to CB address + + +/* +for (byte i = 0; i < Settings.knx_CB_registered; ++i) +{ + j = Settings.knx_CB_param[i]; + if ( j > 0 ) + { + device_param[j-1].CB_id = knx.callback_register("", KNX_CB_Action, &device_param[j-1]); // KNX IP Library requires a parameter + // to identify which action was requested on the KNX network + // to be performed on this device (set relay, etc.) + // Is going to be used device_param[j].type that stores the type number (1: relay 1, etc) + KNX_addr.value = Settings.knx_CB_addr[i]; + knx.callback_assign( device_param[j-1].CB_id, KNX_addr ); + } +} +*/ + + + + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "ADD CB: %d/%d/%d to %d"), + CBop, CB_FNUM, CB_AREA, CB_FDEF ); + AddLog(LOG_LEVEL_INFO); + +} + + +void KNX_DEL_CB( byte CBnum ) +{ + //delete assigment + //check if there is no other assigment to that callback. If there is not. delete that callback register + + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "DEL CB %d"), + CBnum ); + AddLog(LOG_LEVEL_INFO); + +} + void KNXStart() { @@ -183,9 +254,13 @@ void KNXStart() knx.start(WebServer, false); // Start knx and pass the webserver object to be used by UDP. False is for not showing the library webpage. #endif -// Read Configuration -// Check which relays, buttons and sensors where configured for this device -// and activate options according to the hardware + // Set Physical KNX Address of the device + KNX_physs_addr.value = Settings.knx_physsical_addr; + knx.physical_address_set( KNX_physs_addr ); + + // Read Configuration + // Check which relays, buttons and sensors where configured for this device + // and activate options according to the hardware for (int i = GPIO_REL1; i < GPIO_REL8 + 1; ++i) { if (GetUsedInModule(i, my_module.gp.io)) { device_param[i - GPIO_REL1].show = true; } @@ -222,10 +297,6 @@ void KNXStart() if ( !device_param[j-1].show ) { Settings.knx_CB_param[i] = 0; } } - // Set Physical KNX Address of the device - KNX_physs_addr.value = Settings.knx_physsical_addr; - knx.physical_address_set( KNX_physs_addr ); - // Register Group Addresses to listen to // Search on the settings if there is a group address set for receive KNX messages for the type: device_param[j].type // If there is, register the group address on the KNX_IP Library to Receive data for Executing Callbacks @@ -376,8 +447,7 @@ void KNX_Sensor(byte sensor_type, float value) const char S_CONFIGURE_KNX[] PROGMEM = D_CONFIGURE_KNX; const char HTTP_FORM_KNX[] PROGMEM = - "
 " D_KNX_PARAMETERS " 
" - "" + "
 " D_KNX_PARAMETERS " " "
" "" D_KNX_PHYSICAL_ADDRESS " " " . " @@ -398,21 +468,21 @@ const char HTTP_FORM_KNX_OPT[] PROGMEM = ""; const char HTTP_FORM_KNX_GA[] PROGMEM = - " / " - " / " - " "; + " / " + " / " + " "; const char HTTP_FORM_KNX_ADD_BTN[] PROGMEM = - "

" + "

" ""; const char HTTP_FORM_KNX_ADD_TABLE_ROW[] PROGMEM = "" - ""; + ""; const char HTTP_FORM_KNX3[] PROGMEM = "
{optex} -> GAfnum / GAarea / GAfdef

" - "
" + "
" "" D_KNX_GROUP_ADDRESS_TO_READ "
"; const char HTTP_FORM_KNX4[] PROGMEM = @@ -420,97 +490,227 @@ const char HTTP_FORM_KNX4[] PROGMEM = const char HTTP_FORM_KNX_ADD_TABLE_ROW2[] PROGMEM = "GAfnum / GAarea / GAfdef -> {optex}" - ""; + ""; void HandleKNXConfiguration() { + char tmp[100]; + String stmp; + if (HTTP_USER == webserver_state) { HandleRoot(); return; } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_KNX); - String page = FPSTR(HTTP_HEAD); - page.replace(F("{v}"), FPSTR(S_CONFIGURE_KNX)); - page += FPSTR(HTTP_HEAD_STYLE); - page.replace(F("340px"), F("530px")); - page += FPSTR(HTTP_FORM_KNX); - page.replace(F("{kna"), String(KNX_physs_addr.pa.area)); - page.replace(F("{knl"), String(KNX_physs_addr.pa.line)); - page.replace(F("{knm"), String(KNX_physs_addr.pa.member)); - if ( Settings.flag.knx_enabled ) { page += F(" checked"); } + if ( WebServer->hasArg("save") ) { + KNX_Save_Settings(); + HandleConfiguration(); + } + else + { + if ( WebServer->hasArg("btn_add") ) { + if ( WebServer->arg("btn_add") == "1" ) { - page += FPSTR(HTTP_FORM_KNX2); - for (byte i = 0; i < KNX_MAX_device_param ; i++) - { - if ( device_param[i].show ) - { - page += FPSTR(HTTP_FORM_KNX_OPT); - page.replace(F("{vop}"), String(device_param[i].type)); - page.replace(F("{nop}"), String(device_param_ga[i])); + stmp = WebServer->arg("GAop"); //option selected + byte GAop = stmp.toInt(); + stmp = WebServer->arg("GA_FNUM"); + byte GA_FNUM = stmp.toInt(); + stmp = WebServer->arg("GA_AREA"); + byte GA_AREA = stmp.toInt(); + stmp = WebServer->arg("GA_FDEF"); + byte GA_FDEF = stmp.toInt(); + + KNX_ADD_GA( GAop, GA_FNUM, GA_AREA, GA_FDEF ); + + } + else + { + + stmp = WebServer->arg("CBop"); //option selected + byte CBop = stmp.toInt(); + stmp = WebServer->arg("CB_FNUM"); + byte CB_FNUM = stmp.toInt(); + stmp = WebServer->arg("CB_AREA"); + byte CB_AREA = stmp.toInt(); + stmp = WebServer->arg("CB_FDEF"); + byte CB_FDEF = stmp.toInt(); + + KNX_ADD_CB( CB_FNUM, CB_AREA, CB_FDEF, CBop ); + + } } - } - page += F(" -> "); - page += FPSTR(HTTP_FORM_KNX_GA); - page += FPSTR(HTTP_FORM_KNX_ADD_BTN); - page.replace(F("{btnval}"), String(1)); - for (byte i = 0; i < Settings.knx_GA_registered ; i++) - { - if ( Settings.knx_GA_param[i] ) + else if ( WebServer->hasArg("btn_del_ga") ) { - page += FPSTR(HTTP_FORM_KNX_ADD_TABLE_ROW); - page.replace(F("{opval}"), String(Settings.knx_GA_param[i])); - page.replace(F("{optex}"), String(device_param_ga[Settings.knx_GA_param[i]-1])); - KNX_addr.value = Settings.knx_GA_addr[i]; - page.replace(F("GAfnum"), String(KNX_addr.ga.area)); - page.replace(F("GAarea"), String(KNX_addr.ga.line)); - page.replace(F("GAfdef"), String(KNX_addr.ga.member)); + + stmp = WebServer->arg("btn_del_ga"); + byte GA_NUM = stmp.toInt(); + + KNX_DEL_GA(GA_NUM); + } - } - page += FPSTR(HTTP_FORM_KNX3); - page += FPSTR(HTTP_FORM_KNX_GA); - page.replace(F("GAfnum"), F("CBfnum")); - page.replace(F("GAarea"), F("CBarea")); - page.replace(F("GAfdef"), F("CBfdef")); - page += FPSTR(HTTP_FORM_KNX4); - for (byte i = 0; i < KNX_MAX_device_param ; i++) - { - if ( device_param[i].show ) + else if ( WebServer->hasArg("btn_del_cb") ) { - page += FPSTR(HTTP_FORM_KNX_OPT); - page.replace(F("{vop}"), String(device_param[i].type)); - page.replace(F("{nop}"), String(device_param_cb[i])); + + stmp = WebServer->arg("btn_del_cb"); + byte CB_NUM = stmp.toInt(); + + KNX_DEL_CB(CB_NUM); + } - } - page += F(" "); - page += FPSTR(HTTP_FORM_KNX_ADD_BTN); - page.replace(F("{btnval}"), String(2)); - for (byte i = 0; i < Settings.knx_CB_registered ; i++) - { - if ( Settings.knx_CB_param[i] ) + + String page = FPSTR(HTTP_HEAD); + page.replace(F("{v}"), FPSTR(S_CONFIGURE_KNX)); + page += FPSTR(HTTP_HEAD_STYLE); + page.replace(F("340px"), F("530px")); + page += FPSTR(HTTP_FORM_KNX); + KNX_physs_addr.value = Settings.knx_physsical_addr; + page.replace(F("{kna"), String(KNX_physs_addr.pa.area)); + page.replace(F("{knl"), String(KNX_physs_addr.pa.line)); + page.replace(F("{knm"), String(KNX_physs_addr.pa.member)); + if ( Settings.flag.knx_enabled ) { page += F(" checked"); } + + page += FPSTR(HTTP_FORM_KNX2); + for (byte i = 0; i < KNX_MAX_device_param ; i++) { - page += FPSTR(HTTP_FORM_KNX_ADD_TABLE_ROW2); - page.replace(F("{opval}"), String(Settings.knx_CB_param[i])); - page.replace(F("{optex}"), String(device_param_cb[Settings.knx_CB_param[i]-1])); - KNX_addr.value = Settings.knx_CB_addr[i]; - page.replace(F("GAfnum"), String(KNX_addr.ga.area)); - page.replace(F("GAarea"), String(KNX_addr.ga.line)); - page.replace(F("GAfdef"), String(KNX_addr.ga.member)); + if ( device_param[i].show ) + { + page += FPSTR(HTTP_FORM_KNX_OPT); + page.replace(F("{vop}"), String(device_param[i].type)); + page.replace(F("{nop}"), String(device_param_ga[i])); + } } + page += F(" -> "); + page += FPSTR(HTTP_FORM_KNX_GA); + page.replace(F("GAfnum"), F("GA_FNUM")); + page.replace(F("GAarea"), F("GA_AREA")); + page.replace(F("GAfdef"), F("GA_FDEF")); + page.replace(F("GAfnum"), F("GA_FNUM")); + page.replace(F("GAarea"), F("GA_AREA")); + page.replace(F("GAfdef"), F("GA_FDEF")); + page += FPSTR(HTTP_FORM_KNX_ADD_BTN); + page.replace(F("{btnval}"), String(1)); + if (Settings.knx_GA_registered < MAX_KNX_GA) { + page.replace(F("btndis"), F(" ")); + } + else + { + page.replace(F("btndis"), F("disabled")); + } + page.replace(F("fncbtnadd"), F("GAwarning")); + for (byte i = 0; i < Settings.knx_GA_registered ; i++) + { + if ( Settings.knx_GA_param[i] ) + { + page += FPSTR(HTTP_FORM_KNX_ADD_TABLE_ROW); + page.replace(F("{opval}"), String(Settings.knx_GA_param[i])); + page.replace(F("{optex}"), String(device_param_ga[Settings.knx_GA_param[i]-1])); + KNX_addr.value = Settings.knx_GA_addr[i]; + page.replace(F("GAfnum"), String(KNX_addr.ga.area)); + page.replace(F("GAarea"), String(KNX_addr.ga.line)); + page.replace(F("GAfdef"), String(KNX_addr.ga.member)); + } + } + page += FPSTR(HTTP_FORM_KNX3); + page += FPSTR(HTTP_FORM_KNX_GA); + page.replace(F("GAfnum"), F("CB_FNUM")); + page.replace(F("GAarea"), F("CB_AREA")); + page.replace(F("GAfdef"), F("CB_FDEF")); + page.replace(F("GAfnum"), F("CB_FNUM")); + page.replace(F("GAarea"), F("CB_AREA")); + page.replace(F("GAfdef"), F("CB_FDEF")); + page += FPSTR(HTTP_FORM_KNX4); + for (byte i = 0; i < KNX_MAX_device_param ; i++) + { + if ( device_param[i].show ) + { + page += FPSTR(HTTP_FORM_KNX_OPT); + page.replace(F("{vop}"), String(device_param[i].type)); + page.replace(F("{nop}"), String(device_param_cb[i])); + } + } + page += F(" "); + page += FPSTR(HTTP_FORM_KNX_ADD_BTN); + page.replace(F("{btnval}"), String(2)); + if (Settings.knx_CB_registered < MAX_KNX_CB) { + page.replace(F("btndis"), F(" ")); + } + else + { + page.replace(F("btndis"), F("disabled")); + } + page.replace(F("fncbtnadd"), F("CBwarning")); + for (byte i = 0; i < Settings.knx_CB_registered ; i++) + { + if ( Settings.knx_CB_param[i] ) + { + page += FPSTR(HTTP_FORM_KNX_ADD_TABLE_ROW2); + page.replace(F("{opval}"), String(Settings.knx_CB_param[i])); + page.replace(F("{optex}"), String(device_param_cb[Settings.knx_CB_param[i]-1])); + KNX_addr.value = Settings.knx_CB_addr[i]; + page.replace(F("GAfnum"), String(KNX_addr.ga.area)); + page.replace(F("GAarea"), String(KNX_addr.ga.line)); + page.replace(F("GAfdef"), String(KNX_addr.ga.member)); + } + } + page += F("
"); + page += F("
"); + page += FPSTR(HTTP_BTN_CONF); + + page.replace( F(""), + F("function GAwarning()" + "{" + "var GA_FNUM = document.getElementById('GA_FNUM');" + "var GA_AREA = document.getElementById('GA_AREA');" + "var GA_FDEF = document.getElementById('GA_FDEF');" + "if ( GA_FNUM != null && GA_FNUM.value == '0' && GA_AREA.value == '0' && GA_FDEF.value == '0' ) {" + "alert('" D_KNX_WARNING "');" + "}" + "}" + "function CBwarning()" + "{" + "var CB_FNUM = document.getElementById('CB_FNUM');" + "var CB_AREA = document.getElementById('CB_AREA');" + "var CB_FDEF = document.getElementById('CB_FDEF');" + "if ( CB_FNUM != null && CB_FNUM.value == '0' && CB_AREA.value == '0' && CB_FDEF.value == '0' ) {" + "alert('" D_KNX_WARNING "');" + "}" + "}" + "") ); + ShowPage(page); } - page += F("
"); - page += FPSTR(HTTP_FORM_END); - page += FPSTR(HTTP_BTN_CONF); - ShowPage(page); } void KNX_Save_Settings() { + String stmp; + address_t KNX_physs_addr; + Settings.flag.knx_enabled = WebServer->hasArg("b1"); + + stmp = WebServer->arg("area"); + KNX_physs_addr.pa.area = stmp.toInt(); + stmp = WebServer->arg("line"); + KNX_physs_addr.pa.line = stmp.toInt(); + stmp = WebServer->arg("member"); + KNX_physs_addr.pa.member = stmp.toInt(); + + Settings.knx_physsical_addr = KNX_physs_addr.value; + // Set Physical KNX Address of the device + knx.physical_address_set( KNX_physs_addr ); + + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "KNX_ENABLED: %d "), + Settings.flag.knx_enabled); + AddLog(LOG_LEVEL_INFO); + + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_KNX "KNX_PHYSADDR: %d.%d.%d "), + KNX_physs_addr.pa.area, KNX_physs_addr.pa.line, KNX_physs_addr.pa.member ); + AddLog(LOG_LEVEL_INFO); } + #endif // USE_WEBSERVER @@ -529,7 +729,7 @@ boolean Xdrv10(byte function) break; case FUNC_LOOP: knx.loop(); // Process knx events - // It is not used by actual config of asyncUDP branch of ESP-KNX-IP Library, + // It is not used by the actual config of asyncUDP branch of ESP-KNX-IP Library, // but is left here for compatibility with upcoming features of ESP-KNX-IP Library break; // case FUNC_COMMAND: