diff --git a/lib/libesp32/berry/default/be_modtab.c b/lib/libesp32/berry/default/be_modtab.c
index 02b25a747..86ce0244f 100644
--- a/lib/libesp32/berry/default/be_modtab.c
+++ b/lib/libesp32/berry/default/be_modtab.c
@@ -144,6 +144,7 @@ extern void be_load_AXP192_class(bvm *vm);
extern void be_load_md5_lib(bvm *vm);
extern void be_load_webclient_lib(bvm *vm);
extern void be_load_tcpclient_lib(bvm *vm);
+extern void be_load_udp_lib(bvm *vm);
extern void be_load_crypto_lib(bvm *vm);
extern void be_load_Leds_ntv_class(bvm *vm);
extern void be_load_Leds_class(bvm *vm);
@@ -197,6 +198,7 @@ BERRY_API void be_load_custom_libs(bvm *vm)
#ifdef USE_WEBCLIENT
be_load_webclient_lib(vm);
be_load_tcpclient_lib(vm);
+ be_load_udp_lib(vm);
#endif // USE_WEBCLIENT
#if defined(USE_ONEWIRE) || defined(USE_DS18x20)
be_load_onewirelib(vm);
diff --git a/lib/libesp32/berry/default/be_udp_lib.cpp b/lib/libesp32/berry/default/be_udp_lib.cpp
new file mode 100644
index 000000000..3c5381cd8
--- /dev/null
+++ b/lib/libesp32/berry/default/be_udp_lib.cpp
@@ -0,0 +1,131 @@
+/********************************************************************
+ * UDP lib
+ *
+ * To use: `d = udp()`
+ *
+ *******************************************************************/
+#include "be_constobj.h"
+
+#ifdef USE_WEBCLIENT
+
+// extern int be_udp_init(bvm *vm);
+// extern int be_udp_deinit(bvm *vm);
+// extern int be_udp_begin(bvm *vm);
+// extern int be_udp_begin_mcast(bvm *vm);
+
+#include
+#include
+#include
+#include "be_mapping.h"
+
+extern "C" {
+
+ // init()
+ WiFiUDP *be_udp_init_ntv(void) {
+ return new WiFiUDP();
+ }
+ int32_t be_udp_init(struct bvm *vm) {
+ return be_call_c_func(vm, (void*) &be_udp_init_ntv, "+.p", "");
+ }
+
+ // deinit()
+ void *be_udp_deinit_ntv(WiFiUDP *udp) {
+ if (udp != nullptr) { delete udp; }
+ return nullptr;
+ }
+ int32_t be_udp_deinit(struct bvm *vm) {
+ return be_call_c_func(vm, (void*) &be_udp_deinit_ntv, "=.p", "");
+ }
+
+ // udp.begin(address:string, port:int) -> nil
+ int32_t be_udp_begin_ntv(WiFiUDP *udp, const char *host, int32_t port) {
+ IPAddress addr(INADDR_ANY);
+ // if no host or host is "" then we defult to INADDR_ANY (0.0.0.0)
+ if(host && (*host != 0) && !WiFiGenericClass::hostByName(host, addr)){
+ return 0;
+ }
+ return udp->begin(addr, port);
+ }
+ int32_t be_udp_begin(struct bvm *vm) {
+ return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".si");
+ }
+
+ // udp.begin_multicast(address:string, port:int) -> nil
+ int32_t be_udp_begin_mcast_ntv(WiFiUDP *udp, const char *host, int32_t port) {
+ IPAddress addr((uint32_t)0);
+ if(!WiFiGenericClass::hostByName(host, addr)){
+ return 0;
+ }
+ return udp->WiFiUDP::beginMulticast(addr, port);
+ }
+ int32_t be_udp_begin_mcast(struct bvm *vm) {
+ return be_call_c_func(vm, (void*) &be_udp_begin_mcast_ntv, "b", ".si");
+ }
+
+ // udp.send(address:string, port:int, payload:bytes) -> bool
+ int32_t be_udp_send_ntv(WiFiUDP *udp, const char *host, int32_t port, const uint8_t* buf, int32_t len) {
+ IPAddress addr((uint32_t)0);
+ if (!WiFiGenericClass::hostByName(host, addr)){
+ return 0;
+ }
+ if (!udp->beginPacket(addr, port)) { return 0; }
+ int bw = udp->write(buf, len);
+ if (!bw) { return 0; }
+ if (!udp->endPacket()) { return 0; }
+ return btrue;
+ }
+ int32_t be_udp_send(struct bvm *vm) {
+ return be_call_c_func(vm, (void*) &be_udp_send_ntv, "b", ".si(bytes)~");
+ }
+
+ // udp.send_multicast(payload:bytes) -> bool
+ int32_t be_udp_send_mcast_ntv(WiFiUDP *udp, const uint8_t* buf, int32_t len) {
+ if (!udp->beginMulticastPacket()) { return 0; }
+ int bw = udp->write(buf, len);
+ if (!bw) { return 0; }
+ if (!udp->endPacket()) { return 0; }
+ return btrue;
+ }
+ int32_t be_udp_send_mcast(struct bvm *vm) {
+ return be_call_c_func(vm, (void*) &be_udp_send_mcast_ntv, "b", ".(bytes)~");
+ }
+
+ // udp.read() -> bytes or nil
+ int32_t be_udp_read(struct bvm *vm) {
+ WiFiUDP *udp = (WiFiUDP*) be_convert_single_elt(vm, 1, NULL, NULL);
+ if (udp->parsePacket()) {
+ int btr = udp->available();
+ uint8_t * buf = (uint8_t*) be_pushbuffer(vm, btr);
+ int32_t btr2 = udp->read(buf, btr);
+ be_pushbytes(vm, buf, btr2);
+ be_return(vm); /* return code */
+ } else {
+ be_return_nil(vm);
+ }
+ }
+
+ #include "../generate/be_fixed_be_class_udp.h"
+
+ void be_load_udp_lib(bvm *vm) {
+ be_pushntvclass(vm, &be_class_udp);
+ be_setglobal(vm, "udp");
+ be_pop(vm, 1);
+ }
+}
+/* @const_object_info_begin
+
+class be_class_udp (scope: global, name: udp) {
+ .p, var
+ init, func(be_udp_init)
+ deinit, func(be_udp_deinit)
+
+ send, func(be_udp_send)
+ send_multicast, func(be_udp_send_mcast)
+
+ begin, func(be_udp_begin)
+ begin_multicast, func(be_udp_begin_mcast)
+ read, func(be_udp_read)
+}
+@const_object_info_end */
+
+#endif // USE_WEBCLIENT
diff --git a/lib/libesp32/berry/generate/be_const_strtab.h b/lib/libesp32/berry/generate/be_const_strtab.h
index 430c08944..7b7783c0d 100644
--- a/lib/libesp32/berry/generate/be_const_strtab.h
+++ b/lib/libesp32/berry/generate/be_const_strtab.h
@@ -236,6 +236,7 @@ extern const bcstring be_const_str_back_forth;
extern const bcstring be_const_str_base_class;
extern const bcstring be_const_str_battery_present;
extern const bcstring be_const_str_begin;
+extern const bcstring be_const_str_begin_multicast;
extern const bcstring be_const_str_bool;
extern const bcstring be_const_str_break;
extern const bcstring be_const_str_bri;
@@ -595,6 +596,8 @@ extern const bcstring be_const_str_search;
extern const bcstring be_const_str_sec;
extern const bcstring be_const_str_seg7_font;
extern const bcstring be_const_str_select;
+extern const bcstring be_const_str_send;
+extern const bcstring be_const_str_send_multicast;
extern const bcstring be_const_str_serial;
extern const bcstring be_const_str_set;
extern const bcstring be_const_str_set_alternate;
@@ -680,6 +683,7 @@ extern const bcstring be_const_str_true;
extern const bcstring be_const_str_try;
extern const bcstring be_const_str_try_rule;
extern const bcstring be_const_str_type;
+extern const bcstring be_const_str_udp;
extern const bcstring be_const_str_unknown_X20instruction;
extern const bcstring be_const_str_update;
extern const bcstring be_const_str_upper;
diff --git a/lib/libesp32/berry/generate/be_const_strtab_def.h b/lib/libesp32/berry/generate/be_const_strtab_def.h
index 822b96cde..33f93e63b 100644
--- a/lib/libesp32/berry/generate/be_const_strtab_def.h
+++ b/lib/libesp32/berry/generate/be_const_strtab_def.h
@@ -1,635 +1,638 @@
-be_define_const_str(, "", 2166136261u, 0, 0, &be_const_str_True);
-be_define_const_str(_X0A, "\n", 252472541u, 0, 1, &be_const_str_i2c_enabled);
-be_define_const_str(_X20, " ", 621580159u, 0, 1, &be_const_str_add_cmd);
-be_define_const_str(_X21_X3D, "!=", 2428715011u, 0, 2, &be_const_str__X23autoexec_X2Ebe);
-be_define_const_str(_X21_X3D_X3D, "!==", 559817114u, 0, 3, &be_const_str__X2Ew);
-be_define_const_str(_X23, "#", 638357778u, 0, 1, &be_const_str_gpio);
-be_define_const_str(_X23autoexec_X2Ebat, "#autoexec.bat", 3382890497u, 0, 13, NULL);
-be_define_const_str(_X23autoexec_X2Ebe, "#autoexec.be", 1181757091u, 0, 12, &be_const_str_assert);
-be_define_const_str(_X23display_X2Eini, "#display.ini", 182218220u, 0, 12, &be_const_str_code);
-be_define_const_str(_X23init_X2Ebat, "#init.bat", 3297595077u, 0, 9, &be_const_str__X2502d_X25s_X2502d);
-be_define_const_str(_X23preinit_X2Ebe, "#preinit.be", 687035716u, 0, 11, &be_const_str__timers);
-be_define_const_str(_X2502d_X25s_X2502d, "%02d%s%02d", 1587999717u, 0, 10, &be_const_str__X3D_X3C_X3E_X21);
-be_define_const_str(_X2504d_X2D_X2502d_X2D_X2502dT_X2502d_X3A_X2502d_X3A_X2502d, "%04d-%02d-%02dT%02d:%02d:%02d", 3425528601u, 0, 29, &be_const_str_get_object_from_ptr);
-be_define_const_str(_X25s_X2Eautoconf, "%s.autoconf", 3560383524u, 0, 11, &be_const_str_RES_OK);
-be_define_const_str(_X26lt_X3BError_X3A_X20apply_X20new_X20or_X20remove_X26gt_X3B, "<Error: apply new or remove>", 2855507949u, 0, 34, &be_const_str_hs2rgb);
-be_define_const_str(_X26lt_X3BNone_X26gt_X3B, "<None>", 2602165498u, 0, 12, &be_const_str__X2Fac);
-be_define_const_str(_X28_X29, "()", 685372826u, 0, 2, NULL);
-be_define_const_str(_X2B, "+", 772578730u, 0, 1, &be_const_str_lower);
-be_define_const_str(_X2C, ",", 688690635u, 0, 1, &be_const_str_SERIAL_7O1);
-be_define_const_str(_X2D_X2D_X3A_X2D_X2D, "--:--", 1370615441u, 0, 5, &be_const_str__X3Cp_X3ECurrent_X20configuration_X3A_X20_X3C_X2Fp_X3E_X3Cp_X3E_X3Cb_X3E_X25s_X3C_X2Fb_X3E_X3C_X2Fp_X3E);
-be_define_const_str(_X2E, ".", 722245873u, 0, 1, &be_const_str_search);
-be_define_const_str(_X2E_X2E, "..", 2748622605u, 0, 2, &be_const_str__debug_present);
-be_define_const_str(_X2Eautoconf, ".autoconf", 2524679088u, 0, 9, &be_const_str_false);
-be_define_const_str(_X2Ebe, ".be", 1325797348u, 0, 3, &be_const_str_Tasmota);
-be_define_const_str(_X2Ebec, ".bec", 3985273221u, 0, 4, &be_const_str_CFG_X3A_X20downloading_X20_X27_X25s_X27);
-be_define_const_str(_X2Elen, ".len", 850842136u, 0, 4, &be_const_str__X3Cselect_X20name_X3D_X27zip_X27_X3E);
-be_define_const_str(_X2Ep, ".p", 1171526419u, 0, 2, NULL);
-be_define_const_str(_X2Ep1, ".p1", 249175686u, 0, 3, &be_const_str__t);
-be_define_const_str(_X2Ep2, ".p2", 232398067u, 0, 3, &be_const_str_BRY_X3A_X20could_X20not_X20save_X20compiled_X20file_X20_X25s_X20_X28_X25s_X29);
-be_define_const_str(_X2Esize, ".size", 1965188224u, 0, 5, &be_const_str_is_first_time);
-be_define_const_str(_X2Etapp, ".tapp", 1363391594u, 0, 5, &be_const_str__X7B);
-be_define_const_str(_X2Ew, ".w", 1255414514u, 0, 2, &be_const_str_clear);
-be_define_const_str(_X2F, "/", 705468254u, 0, 1, &be_const_str_SERIAL_7O2);
-be_define_const_str(_X2F_X2Eautoconf, "/.autoconf", 2212074393u, 0, 10, &be_const_str_CFG_X3A_X20exception_X20_X27_X25s_X27_X20_X2D_X20_X27_X25s_X27);
+be_define_const_str(, "", 2166136261u, 0, 0, &be_const_str__X2Ep);
+be_define_const_str(_X0A, "\n", 252472541u, 0, 1, &be_const_str_https_X3A_X2F_X2Fraw_X2Egithubusercontent_X2Ecom_X2Ftasmota_X2Fautoconf_X2Fmain_X2F_X25s_X2F_X25s_X2Eautoconf);
+be_define_const_str(_X20, " ", 621580159u, 0, 1, &be_const_str_SERIAL_5O1);
+be_define_const_str(_X21_X3D, "!=", 2428715011u, 0, 2, &be_const_str_editable);
+be_define_const_str(_X21_X3D_X3D, "!==", 559817114u, 0, 3, &be_const_str_target);
+be_define_const_str(_X23, "#", 638357778u, 0, 1, &be_const_str_Tasmota);
+be_define_const_str(_X23autoexec_X2Ebat, "#autoexec.bat", 3382890497u, 0, 13, &be_const_str_bool);
+be_define_const_str(_X23autoexec_X2Ebe, "#autoexec.be", 1181757091u, 0, 12, NULL);
+be_define_const_str(_X23display_X2Eini, "#display.ini", 182218220u, 0, 12, NULL);
+be_define_const_str(_X23init_X2Ebat, "#init.bat", 3297595077u, 0, 9, NULL);
+be_define_const_str(_X23preinit_X2Ebe, "#preinit.be", 687035716u, 0, 11, NULL);
+be_define_const_str(_X2502d_X25s_X2502d, "%02d%s%02d", 1587999717u, 0, 10, &be_const_str_get_option);
+be_define_const_str(_X2504d_X2D_X2502d_X2D_X2502dT_X2502d_X3A_X2502d_X3A_X2502d, "%04d-%02d-%02dT%02d:%02d:%02d", 3425528601u, 0, 29, &be_const_str_init);
+be_define_const_str(_X25s_X2Eautoconf, "%s.autoconf", 3560383524u, 0, 11, &be_const_str_quality);
+be_define_const_str(_X26lt_X3BError_X3A_X20apply_X20new_X20or_X20remove_X26gt_X3B, "<Error: apply new or remove>", 2855507949u, 0, 34, NULL);
+be_define_const_str(_X26lt_X3BNone_X26gt_X3B, "<None>", 2602165498u, 0, 12, &be_const_str_del);
+be_define_const_str(_X28_X29, "()", 685372826u, 0, 2, &be_const_str_OneWire);
+be_define_const_str(_X2B, "+", 772578730u, 0, 1, &be_const_str_add);
+be_define_const_str(_X2C, ",", 688690635u, 0, 1, &be_const_str__X2F_X3Frst_X3D);
+be_define_const_str(_X2D_X2D_X3A_X2D_X2D, "--:--", 1370615441u, 0, 5, &be_const_str__X3C_X2Fform_X3E_X3C_X2Fp_X3E);
+be_define_const_str(_X2E, ".", 722245873u, 0, 1, NULL);
+be_define_const_str(_X2E_X2E, "..", 2748622605u, 0, 2, &be_const_str__rules);
+be_define_const_str(_X2Eautoconf, ".autoconf", 2524679088u, 0, 9, &be_const_str__X2Ep1);
+be_define_const_str(_X2Ebe, ".be", 1325797348u, 0, 3, NULL);
+be_define_const_str(_X2Ebec, ".bec", 3985273221u, 0, 4, &be_const_str_autoexec);
+be_define_const_str(_X2Elen, ".len", 850842136u, 0, 4, &be_const_str_set_chg_current);
+be_define_const_str(_X2Ep, ".p", 1171526419u, 0, 2, &be_const_str_get_bri);
+be_define_const_str(_X2Ep1, ".p1", 249175686u, 0, 3, &be_const_str_sec);
+be_define_const_str(_X2Ep2, ".p2", 232398067u, 0, 3, &be_const_str_get_battery_chargin_status);
+be_define_const_str(_X2Esize, ".size", 1965188224u, 0, 5, &be_const_str_calldepth);
+be_define_const_str(_X2Etapp, ".tapp", 1363391594u, 0, 5, &be_const_str_SERIAL_6E1);
+be_define_const_str(_X2Ew, ".w", 1255414514u, 0, 2, &be_const_str_settings);
+be_define_const_str(_X2F, "/", 705468254u, 0, 1, &be_const_str_SERIAL_7N1);
+be_define_const_str(_X2F_X2Eautoconf, "/.autoconf", 2212074393u, 0, 10, &be_const_str_content_send_style);
be_define_const_str(_X2F_X3Frst_X3D, "/?rst=", 580074707u, 0, 6, &be_const_str_SERIAL_7N2);
-be_define_const_str(_X2Fac, "/ac", 3904651978u, 0, 3, &be_const_str_WS2812);
-be_define_const_str(_X3A, ":", 1057798253u, 0, 1, &be_const_str_AudioFileSourceFS);
-be_define_const_str(_X3C, "<", 957132539u, 0, 1, &be_const_str_digital_write);
-be_define_const_str(_X3C_X2Fform_X3E_X3C_X2Fp_X3E, "
", 3546571739u, 0, 11, &be_const_str_LVG_X3A_X20call_X20to_X20unsupported_X20callback);
-be_define_const_str(_X3C_X2Fselect_X3E_X3Cp_X3E_X3C_X2Fp_X3E, "", 1863865923u, 0, 16, &be_const_str_rule);
-be_define_const_str(_X3C_X3D, "<=", 2499223986u, 0, 2, &be_const_str_set_chg_current);
-be_define_const_str(_X3Cbutton_X20name_X3D_X27reapply_X27_X20class_X3D_X27button_X20bgrn_X27_X3ERe_X2Dapply_X20current_X20configuration_X3C_X2Fbutton_X3E, "", 3147934216u, 0, 82, &be_const_str_find_op);
-be_define_const_str(_X3Cbutton_X20name_X3D_X27zipapply_X27_X20class_X3D_X27button_X20bgrn_X27_X3EApply_X20configuration_X3C_X2Fbutton_X3E, "", 1205771629u, 0, 72, NULL);
-be_define_const_str(_X3Cfieldset_X3E_X3Cstyle_X3E_X2Ebdis_X7Bbackground_X3A_X23888_X3B_X7D_X2Ebdis_X3Ahover_X7Bbackground_X3A_X23888_X3B_X7D_X3C_X2Fstyle_X3E, "", 2052843416u, 0, 25, &be_const_str_button_pressed);
-be_define_const_str(_X3Cp_X3E_X3Cform_X20id_X3Dac_X20action_X3D_X27ac_X27_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20method_X3D_X27get_X27_X3E_X3Cbutton_X3E_X26_X23129668_X3B_X20Auto_X2Dconfiguration_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E, "", 452285201u, 0, 120, NULL);
-be_define_const_str(_X3Cp_X3E_X3Cform_X20id_X3Dreapply_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20action_X3D_X27_X2Fac_X27_X20method_X3D_X27post_X27_X20, "", 3546571739u, 0, 11, &be_const_str_resolvecmnd);
+be_define_const_str(_X3C_X2Fselect_X3E_X3Cp_X3E_X3C_X2Fp_X3E, "", 1863865923u, 0, 16, &be_const_str_f);
+be_define_const_str(_X3C_X3D, "<=", 2499223986u, 0, 2, &be_const_str_exp);
+be_define_const_str(_X3Cbutton_X20name_X3D_X27reapply_X27_X20class_X3D_X27button_X20bgrn_X27_X3ERe_X2Dapply_X20current_X20configuration_X3C_X2Fbutton_X3E, "", 3147934216u, 0, 82, &be_const_str__X3Cp_X3E_X3Csmall_X3E_X26nbsp_X3B_X28This_X20feature_X20requires_X20an_X20internet_X20connection_X29_X3C_X2Fsmall_X3E_X3C_X2Fp_X3E);
+be_define_const_str(_X3Cbutton_X20name_X3D_X27zipapply_X27_X20class_X3D_X27button_X20bgrn_X27_X3EApply_X20configuration_X3C_X2Fbutton_X3E, "", 1205771629u, 0, 72, &be_const_str_CFG_X3A_X20removed_X20file_X20_X27_X25s_X27);
+be_define_const_str(_X3Cfieldset_X3E_X3Cstyle_X3E_X2Ebdis_X7Bbackground_X3A_X23888_X3B_X7D_X2Ebdis_X3Ahover_X7Bbackground_X3A_X23888_X3B_X7D_X3C_X2Fstyle_X3E, "", 2052843416u, 0, 25, &be_const_str__X3Cselect_X20name_X3D_X27zip_X27_X3E);
+be_define_const_str(_X3Cp_X3E_X3Cform_X20id_X3Dac_X20action_X3D_X27ac_X27_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20method_X3D_X27get_X27_X3E_X3Cbutton_X3E_X26_X23129668_X3B_X20Auto_X2Dconfiguration_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E, "", 452285201u, 0, 120, &be_const_str_I2C_X3A);
+be_define_const_str(_X3Cp_X3E_X3Cform_X20id_X3Dreapply_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20action_X3D_X27_X2Fac_X27_X20method_X3D_X27post_X27_X20, "