wire1 or wire2 or nil
+ # scan for the first occurrence of the addr, starting with bus1 then bus2
+ # optional: skip if index is disabled via I2CEnable
+ def wire_scan(addr,idx)
+ # skip if the I2C index is disabled
+ if idx != nil && !self.i2c_enabled(idx) return nil end
+ if self.wire1.enabled() && self.wire1.detect(addr) return self.wire1 end
+ if self.wire2.enabled() && self.wire2.detect(addr) return self.wire2 end
+ return nil
+ end
+
+ def time_str(time)
+ import string
+ var tm = self.time_dump(time)
+ return string.format("%04d-%02d-%02dT%02d:%02d:%02d", tm['year'], tm['month'], tm['day'], tm['hour'], tm['min'], tm['sec'])
+ end
+
+ def load(f)
+ # embedded functions
+ # puth_path: adds the current archive to sys.path
+ def push_path(p)
+ import sys
+ var path = sys.path()
+ if path.find(p) == nil # append only if it's not already there
+ path.push(p)
+ end
+ end
+ # pop_path: removes the path
+ def pop_path(p)
+ import sys
+ var path = sys.path()
+ var idx = path.find(p)
+ if idx != nil
+ path.remove(idx)
+ end
+ end
+
+ import string
+ import path
+
+ # fail if empty string
+ if size(f) == 0 return false end
+ # Ex: f = 'app.zip#autoexec'
+
+ # add leading '/' if absent
+ if f[0] != '/' f = '/' + f end
+ # Ex: f = '/app.zip#autoexec'
+
+ var f_items = string.split(f, '#')
+ var f_prefix = f_items[0]
+ var f_suffix = f_items[-1] # last token
+ var f_archive = size(f_items) > 1 # is the file in an archive
+
+ # if no dot, add the default '.be' extension
+ if string.find(f_suffix, '.') < 0 # does the final file has a '.'
+ f += ".be"
+ f_suffix += ".be"
+ end
+ # Ex: f = '/app.zip#autoexec.be'
+
+ # if the filename has no '.' append '.be'
+ var suffix_be = f_suffix[-3..-1] == '.be'
+ var suffix_bec = f_suffix[-4..-1] == '.bec'
+ # Ex: f = '/app.zip#autoexec.be', f_suffix = 'autoexec.be', suffix_be = true, suffix_bec = false
+
+ # check that the file ends with '.be' of '.bec'
+ if !suffix_be && !suffix_bec
+ raise "io_error", "file extension is not '.be' or '.bec'"
+ end
+
+ var f_time = path.last_modified(f_prefix)
+
+ if suffix_bec
+ if f_time == nil return false end # file does not exist
+ # f is the right file, continue
+ else
+ var f_time_bc = path.last_modified(f + "c") # timestamp for bytecode
+ if f_time == nil && f_time_bc == nil return false end
+ if f_time_bc != nil && (f_time == nil || f_time_bc >= f_time)
+ # bytecode exists and is more recent than berry source, use bytecode
+ ##### temporarily disable loading from bec file
+ # f = f + "c" # use bytecode name
+ suffix_bec = true
+ end
+ end
+
+ # recall the working directory
+ if f_archive
+ self.wd = f_prefix + "#"
+ push_path(self.wd)
+ else
+ self.wd = ""
+ end
+
+ var c = compile(f, 'file')
+ # save the compiled bytecode
+ if !suffix_bec && !f_archive
+ try
+ self.save(f + 'c', c)
+ except .. as e
+ print(string.format('BRY: could not save compiled file %s (%s)',f+'c',e))
+ end
+ end
+ # call the compiled code
+ c()
+ # call successfuls
+
+ # remove path prefix
+ if f_archive
+ pop_path(f_prefix + "#")
+ end
+
+ return true
+ end
+
+ def event(event_type, cmd, idx, payload, raw)
+ import introspect
+ import string
+ if event_type=='every_50ms' self.run_deferred() end #- first run deferred events -#
+
+ var done = false
+ if event_type=='cmd' return self.exec_cmd(cmd, idx, payload)
+ elif event_type=='tele' return self.exec_tele(payload)
+ elif event_type=='rule' return self.exec_rules(payload)
+ elif event_type=='gc' return self.gc()
+ elif self._drivers
+ var i = 0
+ while i < size(self._drivers)
+ #for d:self._drivers
+ var d = self._drivers[i]
+ var f = introspect.get(d, event_type) # try to match a function or method with the same name
+ if type(f) == 'function'
+ try
+ done = f(d, cmd, idx, payload, raw)
+ if done break end
+ except .. as e,m
+ print(string.format("BRY: Exception> '%s' - %s", e, m))
+ if self._debug_present
+ import debug
+ debug.traceback()
+ end
+ end
+ end
+ i += 1
+ end
+ end
+
+ # save persist
+ if event_type=='save_before_restart'
+ import persist
+ persist.save()
+ end
+
+ return done
+ end
+
+ def add_driver(d)
+ if self._drivers
+ self._drivers.push(d)
+ else
+ self._drivers = [d]
+ end
+ end
+
+ def remove_driver(d)
+ if self._drivers
+ var idx = self._drivers.find(d)
+ if idx != nil
+ self._drivers.pop(idx)
+ end
+ end
+ end
+
+ # cmd high-level function
+ def cmd(command)
+ self.cmd_res = true # signal buffer capture
+
+ self._cmd(command)
+
+ var ret = nil
+ if self.cmd_res != true # unchanged
+ ret = self.cmd_res
+ end
+ self.cmd_res = nil # clear buffer
+
+ return ret
+ end
+
+ # set_light and get_light deprecetaion
+ def get_light(l)
+ print('tasmota.get_light() is deprecated, use light.get()')
+ import light
+ if l != nil
+ return light.get(l)
+ else
+ return light.get()
+ end
+ end
+ def set_light(v,l)
+ print('tasmota.set_light() is deprecated, use light.set()')
+ import light
+ if l != nil
+ return light.set(v,l)
+ else
+ return light.set(v)
+ end
+ end
+
+ #- generate a new C callback and record the associated Berry closure -#
+ def gen_cb(f)
+ # DEPRECATED
+ import cb
+ return cb.gen_cb(f)
+ end
+
+ #- convert hue/sat to rgb -#
+ #- hue:int in range 0..359 -#
+ #- sat:int (optional) in range 0..255 -#
+ #- returns int: 0xRRGGBB -#
+ def hs2rgb(hue,sat)
+ if sat == nil sat = 255 end
+ var r = 255 # default to white
+ var b = 255
+ var g = 255
+ # we take brightness at 100%, brightness should be set separately
+ hue = hue % 360 # normalize to 0..359
+
+ if sat > 0
+ var i = hue / 60 # quadrant 0..5
+ var f = hue % 60 # 0..59
+ var p = 255 - sat
+ var q = tasmota.scale_uint(f, 0, 60, 255, p) # 0..59
+ var t = tasmota.scale_uint(f, 0, 60, p, 255)
+
+ if i == 0
+ # r = 255
+ g = t
+ b = p
+ elif i == 1
+ r = q
+ # g = 255
+ b = p
+ elif i == 2
+ r = p
+ #g = 255
+ b = t
+ elif i == 3
+ r = p
+ g = q
+ #b = 255
+ elif i == 4
+ r = t
+ g = p
+ #b = 255
+ else
+ #r = 255
+ g = p
+ b = q
+ end
+ end
+
+ return (r << 16) | (g << 8) | b
+ end
+end
diff --git a/lib/libesp32/berry/default/embedded/Wire.be b/lib/libesp32/berry/default/embedded/Wire.be
new file mode 100644
index 000000000..a5e28ddd8
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/Wire.be
@@ -0,0 +1,25 @@
+#- Native code used for testing and code solidification -#
+#- Do not use it -#
+
+class Wire
+ var bus
+
+ def read_bytes(addr,reg,size)
+ self._begin_transmission(addr)
+ self._write(reg)
+ self._end_transmission(false)
+ self._request_from(addr,size)
+ var ret=bytes(size)
+ while (self._available())
+ ret..self._read()
+ end
+ return ret
+ end
+
+ def write_bytes(addr,reg,b)
+ self._begin_transmission(addr)
+ self._write(reg)
+ self._write(b)
+ self._end_transmission()
+ end
+end
diff --git a/lib/libesp32/berry/default/embedded/autoconf.be b/lib/libesp32/berry/default/embedded/autoconf.be
new file mode 100644
index 000000000..8489c7447
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/autoconf.be
@@ -0,0 +1,389 @@
+#- autocong module for Berry -#
+#- -#
+#- To solidify: -#
+#-
+ # load only persis_module and persist_module.init
+ import autoconf
+ solidify.dump(autoconf_module)
+ # copy and paste into `be_autoconf_lib.c`
+-#
+#-
+
+# For external compile:
+
+display = module("display")
+self = nil
+tasmota = nil
+def load() end
+
+-#
+
+var autoconf_module = module("autoconf")
+
+autoconf_module.init = def (m)
+
+ class Autoconf
+ var _archive
+ var _error
+
+ def init()
+ import path
+ import string
+
+ var dir = path.listdir("/")
+ var entry
+ tasmota.add_driver(self)
+
+ var i = 0
+ while i < size(dir)
+ if string.find(dir[i], ".autoconf") > 0 # does the file contain '*.autoconf', >0 to skip `.autoconf`
+ if entry != nil
+ # we have multiple configuration files, not allowed
+ print(string.format("CFG: multiple autoconf files found, aborting ('%s' + '%s')", entry, dir[i]))
+ self._error = true
+ return nil
+ end
+ entry = dir[i]
+ end
+ i += 1
+ end
+
+ if entry == nil
+ tasmota.log("CFG: no '*.autoconf' file found", 2)
+ return nil
+ end
+
+ self._archive = entry
+ end
+
+
+ # ####################################################################################################
+ # Manage first time marker
+ # ####################################################################################################
+ def is_first_time()
+ import path
+ return !path.exists("/.autoconf")
+ end
+ def set_first_time()
+ var f = open("/.autoconf", "w")
+ f.close()
+ end
+ def clear_first_time()
+ import path
+ path.remove("/.autoconf")
+ end
+
+ # ####################################################################################################
+ # Delete all autoconfig files present
+ # ####################################################################################################
+ def delete_all_configs()
+ import path
+ import string
+ var dir = path.listdir("/")
+
+ for d:dir
+ if string.find(d, ".autoconf") > 0 # does the file contain '*.autoconf'
+ path.remove(d)
+ end
+ end
+ end
+
+ # ####################################################################################################
+ # Get current module
+ # contains the name of the archive without leading `/`, ex: `M5Stack_Fire.autoconf`
+ # or `nil` if none
+ # ####################################################################################################
+ def get_current_module_path()
+ return self._archive
+ end
+ def get_current_module_name()
+ return self._archive[0..-10]
+ end
+
+ # ####################################################################################################
+ # Load templates from Github
+ # ####################################################################################################
+ def load_templates()
+ import string
+ import json
+ try
+ var url = string.format("https://raw.githubusercontent.com/tasmota/autoconf/main/%s_manifest.json", tasmota.arch())
+ tasmota.log(string.format("CFG: loading '%s'", url), 3)
+ # load the template
+ var cl = webclient()
+ cl.begin(url)
+ var r = cl.GET()
+ if r != 200
+ tasmota.log(string.format("CFG: return_code=%i", r), 2)
+ return nil
+ end
+ var s = cl.get_string()
+ cl.close()
+ # convert to json
+ var j = json.load(s)
+ tasmota.log(string.format("CFG: loaded '%s'", str(j)), 3)
+
+ var t = j.find("files")
+ if isinstance(t, list)
+ return t
+ end
+
+ return nil
+ except .. as e, m
+ tasmota.log(string.format("CFG: exception '%s' - '%s'", e, m), 2)
+ return nil
+ end
+ end
+
+ # ####################################################################################################
+ # Init web handlers
+ # ####################################################################################################
+ # Displays a "Autocong" button on the configuration page
+ def web_add_config_button()
+ import webserver
+ webserver.content_send("")
+ end
+
+
+ # This HTTP GET manager controls which web controls are displayed
+ def page_autoconf_mgr()
+ import webserver
+ import string
+ if !webserver.check_privileged_access() return nil end
+
+ webserver.content_start('Auto-configuration')
+ webserver.content_send_style()
+ webserver.content_send(" (This feature requires an internet connection)
")
+
+ var cur_module = self.get_current_module_path()
+ var cur_module_display = cur_module ? string.tr(self.get_current_module_name(), "_", " ") : self._error ? "<Error: apply new or remove>" : "<None>"
+
+ webserver.content_send("")
+
+ webserver.content_send("")
+ webserver.content_button(webserver.BUTTON_CONFIGURATION)
+ webserver.content_stop()
+ end
+
+ # ####################################################################################################
+ # Web controller
+ #
+ # Applies the changes and restart
+ # ####################################################################################################
+ # This HTTP POST manager handles the submitted web form data
+ def page_autoconf_ctl()
+ import webserver
+ import string
+ import path
+ if !webserver.check_privileged_access() return nil end
+
+ try
+ if webserver.has_arg("reapply")
+ tasmota.log("CFG: removing first time marker", 2);
+ # print("CFG: removing first time marker")
+ self.clear_first_time()
+ #- and force restart -#
+ webserver.redirect("/?rst=")
+
+ elif webserver.has_arg("zip")
+ # remove any remaining autoconf file
+ tasmota.log("CFG: removing autoconf files", 2);
+ # print("CFG: removing autoconf files")
+ self.delete_all_configs()
+
+ # get the name of the configuration file
+ var arch_name = webserver.arg("zip")
+
+ if arch_name != "reset"
+ var url = string.format("https://raw.githubusercontent.com/tasmota/autoconf/main/%s/%s.autoconf", tasmota.arch(), arch_name)
+ tasmota.log(string.format("CFG: downloading '%s'", url), 2);
+
+ var local_file = string.format("%s.autoconf", arch_name)
+
+ # download file and write directly to file system
+ var cl = webclient()
+ cl.begin(url)
+ var r = cl.GET()
+ if r != 200 raise "connection_error", string.format("return code=%i", r) end
+ cl.write_file(local_file)
+ cl.close()
+ end
+
+ # remove marker to reapply template
+ self.clear_first_time()
+
+ #- and force restart -#
+ webserver.redirect("/?rst=")
+ else
+ raise "value_error", "Unknown command"
+ end
+ except .. as e, m
+ print(string.format("CFG: Exception> '%s' - %s", e, m))
+ #- display error page -#
+ webserver.content_start("Parameter error") #- title of the web page -#
+ webserver.content_send_style() #- send standard Tasmota styles -#
+
+ webserver.content_send(string.format("Exception:
'%s'
%s
", e, m))
+
+ webserver.content_button(webserver.BUTTON_CONFIGURATION) #- button back to management page -#
+ webserver.content_stop() #- end of web page -#
+ end
+ end
+
+ # Add HTTP POST and GET handlers
+ def web_add_handler()
+ import webserver
+ webserver.on('/ac', / -> self.page_autoconf_mgr(), webserver.HTTP_GET)
+ webserver.on('/ac', / -> self.page_autoconf_ctl(), webserver.HTTP_POST)
+ end
+
+
+ # reset the configuration information (but don't restart)
+ # i.e. remove any autoconf file
+ def reset()
+ import path
+ import string
+
+ var dir = path.listdir("/")
+ var entry
+
+ var i = 0
+ while i < size(dir)
+ var fname = dir[i]
+ if string.find(fname, ".autoconf") > 0 # does the file contain '*.autoconf'
+ path.remove(fname)
+ print(string.format("CFG: removed file '%s'", fname))
+ end
+ i += 1
+ end
+
+ self._archive = nil
+ self._error = nil
+ end
+
+ # called by the synthetic event `preinit`
+ def preinit()
+ if self._archive == nil return end
+ # try to launch `preinit.be`
+ import path
+
+ var fname = self._archive + '#preinit.be'
+ if path.exists(fname)
+ tasmota.log("CFG: loading "+fname, 3)
+ load(fname)
+ tasmota.log("CFG: loaded "+fname, 3)
+ end
+ end
+
+ def run_bat(fname) # read a '*.bat' file and run each command
+ import string
+ var f
+ try
+ f = open(fname, "r") # open file in read-only mode, it is expected to exist
+ while true
+ var line = f.readline() # read each line, can contain a terminal '\n', empty if end of file
+ if size(line) == 0 break end # end of file
+
+ if line[-1] == "\n" line = line[0..-2] end # remove any trailing '\n'
+ if size(line) > 0
+ tasmota.cmd(line) # run the command
+ end
+ end
+ f.close() # close, we don't expect exception with read-only, could be added later though
+ except .. as e, m
+ print(string.format('CFG: could not run %s (%s - %s)', fname, e, m))
+ f.close()
+ end
+ end
+
+ # called by the synthetic event `autoexec`
+ def autoexec()
+ if self._archive == nil return end
+ # try to launch `preinit.be`
+ import path
+
+ # Step 1. if first run, only apply `init.bat`
+ var fname = self._archive + '#init.bat'
+ if self.is_first_time() && path.exists(fname)
+ # create the '.autoconf' file to avoid running it again, even if it crashed
+ self.set_first_time()
+
+ # if path.exists(fname) # we know it exists from initial test
+ self.run_bat(fname)
+ tasmota.log("CFG: 'init.bat' done, restarting", 2)
+ tasmota.cmd("Restart 1")
+ return # if init was run, force a restart anyways and don't run the remaining code
+ # end
+ end
+
+ # Step 2. if 'display.ini' is present, launch Universal Display
+ fname = self._archive + '#display.ini'
+ if gpio.pin_used(gpio.OPTION_A, 2) && path.exists(fname)
+ if path.exists("display.ini")
+ tasmota.log("CFG: skipping 'display.ini' because already present in file-system", 2)
+ else
+ import display
+ var f = open(fname,"r")
+ var desc = f.read()
+ f.close()
+ display.start(desc)
+ end
+ end
+
+ # Step 3. if 'autoexec.bat' is present, run it
+ fname = self._archive + '#autoexec.bat'
+ if path.exists(fname)
+ tasmota.log("CFG: running "+fname, 3)
+ self.run_bat(fname)
+ tasmota.log("CFG: ran "+fname, 3)
+ end
+
+ # Step 4. if 'autoexec.be' is present, load it
+ fname = self._archive + '#autoexec.be'
+ if path.exists(fname)
+ tasmota.log("CFG: loading "+fname, 3)
+ load(fname)
+ tasmota.log("CFG: loaded "+fname, 3)
+ end
+ end
+ end
+
+ return Autoconf() # return an instance of this class
+end
+
+aa = autoconf_module.init(autoconf_module)
+import webserver
+webserver.on('/ac2', / -> aa.page_autoconf_mgr(), webserver.HTTP_GET)
+return autoconf_module
diff --git a/lib/libesp32/berry/default/embedded/i2c_axp192.be b/lib/libesp32/berry/default/embedded/i2c_axp192.be
new file mode 100644
index 000000000..3d958334f
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/i2c_axp192.be
@@ -0,0 +1,176 @@
+#-------------------------------------------------------------
+ - Generic driver for AXP192 - solidified
+ -------------------------------------------------------------#
+class AXP192 : I2C_Driver
+ def init()
+ super(self, I2C_Driver).init("AXP192", 0x34)
+ end
+
+ # Return True = Battery Exist
+ def battery_present()
+ if self.wire.read(self.addr, 0x01, 1) & 0x20 return true
+ else return false
+ end
+ end
+
+ # Input Power Status ???
+ def get_input_power_status()
+ return self.wire.read(self.addr, 0x00, 1)
+ end
+
+ # Battery Charging Status
+ def get_battery_chargin_status()
+ return self.wire.read(self.addr, 0x01, 1)
+ end
+
+ # AXP chip temperature in °C
+ def get_temp()
+ return self.read12(0x5E) * 0.1 - 144.7
+ end
+
+ def get_bat_power()
+ return self.read24(0x70) * 0.00055
+ end
+
+ def get_bat_voltage()
+ return self.read12(0x78) * 0.0011
+ end
+ def get_bat_current()
+ return (self.read13(0x7A) - self.read13(0x7C)) * 0.5
+ end
+ def get_bat_charge_current()
+ return self.read13(0x7A) * 0.5
+ end
+ def get_aps_voltage()
+ return self.read12(0x7E) * 0.0014
+ end
+ def get_vbus_voltage()
+ return self.read12(0x5A) * 0.0017
+ end
+ def get_vbus_current()
+ return self.read12(0x5C) * 0.375
+ end
+
+ # set LDO voltage
+ # ldo: 2/3
+ # voltage: (mV) 1800mV - 3300mV in 100mV steps
+ def set_ldo_voltage(ldo, voltage)
+ if voltage > 3300 voltage = 15
+ else voltage = (voltage / 100) - 18
+ end
+
+ if ldo == 2
+ self.write8(0x28, self.read8(0x28) & 0x0F | ((voltage & 0x0F) << 4))
+ end
+ if ldo == 3
+ self.write8(0x28, self.read8(0x28) & 0xF0 | (voltage & 0x0F))
+ end
+ end
+
+ # set DCDC enable, 1/2/3
+ def set_dcdc_enable(dcdc, state)
+ if dcdc == 1 self.write_bit(0x12, 0, state) end
+ if dcdc == 2 self.write_bit(0x12, 4, state) end
+ if dcdc == 3 self.write_bit(0x12, 1, state) end
+ end
+
+ # set LDO enable, 2/3 (LDO 1 is always on)
+ def set_ldo_enable(ldo, state)
+ if ldo == 2 self.write_bit(0x12, 2, state) end
+ if ldo == 3 self.write_bit(0x12, 3, state) end
+ end
+
+ # set GPIO output state 0/1/2 and 3/4
+ def write_gpio(gpio, state)
+ if gpio >= 0 && gpio <= 2
+ self.write_bit(0x94, gpio, state)
+ elif gpio >= 3 && gpio <= 4
+ self.write_bit(0x96, gpio - 3, state)
+ end
+ end
+
+ # Set voltage on DC-DC1/2/3
+ # dcdc: 1/2/3 (warning some C libs start at 0)
+ # voltage:
+ def set_dc_voltage(dcdc, voltage)
+ if dcdc < 1 || dcdc > 3 return end
+ var v
+ if voltage < 700 v = 0
+ elif voltage > 3500 v = 112
+ elif dcdc == 2 && voltage > 2275 v = 63 # dcdc2 is limited to 2.275V
+ else v = (voltage - 700) / 25
+ end
+
+ var addr = 0x26
+ if dcdc == 3 addr = 0x27
+ elif dcdc == 2 addr = 0x23
+ end
+
+ self.write8(addr, self.read8(addr) & 0x80 | (v & 0x7F))
+ end
+
+ # Set charging current
+ # 100mA = 0
+ # 190mA = 1
+ # 280mA = 2
+ # 360mA = 3
+ # 450mA = 4
+ # 550mA = 5
+ # 630mA = 6
+ # 700mA = 7
+ # 780mA = 8
+ # 880mA = 9
+ # 960mA = 10
+ # 1000mA = 11
+ # 1080mA = 12
+ # 1160mA = 13
+ # 1240mA = 14
+ # 1320mA = 15
+ def set_chg_current(current_code)
+ self.write8(0x33, self.read8(0x33) & 0xF0 | (current_code & 0x0F))
+ end
+
+ # // Low Volt Level 1, when APS Volt Output < 3.4496 V
+ # // Low Volt Level 2, when APS Volt Output < 3.3992 V, then this flag is SET (0x01)
+ # // Flag will reset once battery volt is charged above Low Volt Level 1
+ # // Note: now AXP192 have the Shutdown Voltage of 3.0V (B100) Def in REG 31H
+ def get_warning_level()
+ return self.read12(0x47) & 1
+ end
+
+ #- trigger a read every second -#
+ # def every_second()
+ # if !self.wire return nil end #- exit if not initialized -#
+ # end
+
+ #- display sensor value in the web UI -#
+ def web_sensor()
+ if !self.wire return nil end #- exit if not initialized -#
+ import string
+ var msg = string.format(
+ "{s}VBus Voltage{m}%.3f V{e}"..
+ "{s}VBus Current{m}%.1f mA{e}"..
+ "{s}Batt Voltage{m}%.3f V{e}"..
+ "{s}Batt Current{m}%.1f mA{e}"..
+ #"{s}Batt Power{m}%.3f{e}"..
+ "{s}Temp AXP{m}%.1f °C{e}",
+ self.get_vbus_voltage(), self.get_vbus_voltage(),
+ self.get_bat_voltage(), self.get_bat_current(),
+ #self.get_bat_power(),
+ self.get_temp()
+ )
+ tasmota.web_send_decimal(msg)
+ end
+
+ #- add sensor value to teleperiod -#
+ def json_append()
+ if !self.wire return nil end #- exit if not initialized -#
+ # import string
+ # var ax = int(self.accel[0] * 1000)
+ # var ay = int(self.accel[1] * 1000)
+ # var az = int(self.accel[2] * 1000)
+ # var msg = string.format(",\"MPU6886\":{\"AX\":%i,\"AY\":%i,\"AZ\":%i,\"GX\":%i,\"GY\":%i,\"GZ\":%i}",
+ # ax, ay, az, self.gyro[0], self.gyro[1], self.gyro[2])
+ # tasmota.response_append(msg)
+ end
+end
diff --git a/lib/libesp32/berry/default/embedded/i2c_driver.be b/lib/libesp32/berry/default/embedded/i2c_driver.be
new file mode 100644
index 000000000..a66afa5ad
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/i2c_driver.be
@@ -0,0 +1,104 @@
+#-------------------------------------------------------------
+ - IMPORTANT
+ - THIS CLASS IS ALREADY BAKED IN TASMOTA
+ -
+ - It is here for debugging and documentation purpose only
+ -------------------------------------------------------------#
+
+#-------------------------------------------------------------
+ - I2C_Driver class to simplify development of I2C drivers
+ -
+ - I2C_Driver(name, addr [, i2c_index]) -> nil
+ - name: name of I2C device for logging, or function to detect the model
+ - addr: I2C address of device, will probe all I2C buses for it
+ - i2c_index: (optional) check is the device is not disabled
+ -------------------------------------------------------------#
+
+class I2C_Driver
+ var wire #- wire object to reach the device, if nil then the module is not initialized -#
+ var addr #- I2C address of the device -#
+ var name #- model namme of the device, cannot be nil -#
+
+ #- Init and look for device
+ - Input:
+ - name_or_detect : name of the device (if string)
+ or function to detect the precise model(if function)
+ the function is passed a single argument `self`
+ and must return a string, or `nil` if the device is invalid
+ - addr : I2C address of device (int 0..255)
+ - i2c_index : Tasmota I2C index, see `I2CDEVICES.md` (int)
+ --#
+ def init(name_or_detect, addr, i2c_index)
+ var tasmota = self.get_tasmota() #- retrieve the 'tasmota' singleton -#
+
+ #- check if the i2c index is disabled by Tasmota configuration -#
+ if i2c_index != nil && !tasmota.i2c_enabled(i2c_index) return end
+
+ self.addr = addr #- address for AXP192 -#
+ self.wire = tasmota.wire_scan(self.addr) #- get the right I2C bus -#
+
+ if self.wire
+ #- find name of device, can be a string or a method -#
+ if type(name_or_detect) == 'function'
+ self.name = name_or_detect(self)
+ else
+ self.name = name_or_detect
+ end
+ #- if name is invalid, it means we can't detect device, abort -#
+ if self.name == nil self.wire = nil end
+
+ if self.wire
+ print("I2C:", self.name, "detected on bus", self.wire.bus)
+ end
+ end
+ end
+
+ #- write register with 8 bits value -#
+ def write8(reg, val)
+ return self.wire.write(self.addr, reg, val, 1)
+ end
+
+ # Set or clear a specific bit in a register
+ # write_bit(reg:int, bit:int, state:bool) -> nil
+ # reg: I2C register number (0..255)
+ # bit: bit of I2C register to change (0..7)
+ # state: boolean value to write to specified bit
+ def write_bit(reg, bit, state)
+ if bit < 0 || bit > 7 return end
+ var mark = 1 << bit
+ if state self.write8(reg, self.read8(reg) | mark)
+ else self.write8(reg, self.read8(reg) & (0xFF - mark))
+ end
+ end
+
+ # read 8 bits
+ def read8(reg)
+ return self.wire.read(self.addr, reg, 1)
+ end
+ # read 12 bits
+ def read12(reg)
+ var buf = self.wire.read_bytes(self.addr, reg, 2)
+ return (buf[0] << 4) + buf[1]
+ end
+ # read 13 bits
+ def read13(reg)
+ var buf = self.wire.read_bytes(self.addr, reg, 2)
+ return (buf[0] << 5) + buf[1]
+ end
+ # read 24 bits
+ def read24(reg)
+ var buf = self.wire.read_bytes(self.addr, reg, 3)
+ return (buf[0] << 16) + (buf[1] << 8) + buf[2]
+ end
+ # read 32 bits
+ def read32(reg)
+ var buf = self.wire.read_bytes(self.addr, reg, 4)
+ return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]
+ end
+end
+
+#- Example
+
+d = I2C_Driver("MPU", 0x68, 58)
+
+-#
\ No newline at end of file
diff --git a/lib/libesp32/berry/default/embedded/leds.be b/lib/libesp32/berry/default/embedded/leds.be
new file mode 100644
index 000000000..11a0489af
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/leds.be
@@ -0,0 +1,338 @@
+# class Leds
+#
+# for adressable leds like NoePixel
+
+
+# Native commands
+# 00 : ctor (leds:int, gpio:int) -> void
+# 01 : begin void -> void
+# 02 : show void -> void
+# 03 : CanShow void -> bool
+# 04 : IsDirty void -> bool
+# 05 : Dirty void -> void
+# 06 : Pixels void -> bytes() (mapped to the buffer)
+# 07 : PixelSize void -> int
+# 08 : PixelCount void -> int
+# 09 : ClearTo (color:??) -> void
+# 10 : SetPixelColor (idx:int, color:??) -> void
+# 11 : GetPixelColor (idx:int) -> color:??
+# 20 : RotateLeft (rot:int [, first:int, last:int]) -> void
+# 21 : RotateRight (rot:int [, first:int, last:int]) -> void
+# 22 : ShiftLeft (rot:int [, first:int, last:int]) -> void
+# 23 : ShiftRight (rot:int [, first:int, last:int]) -> void
+
+
+class Leds : Leds_ntv
+ var gamma # if true, apply gamma (true is default)
+ var leds # number of leds
+ # leds:int = number of leds of the strip
+ # gpio:int (optional) = GPIO for NeoPixel. If not specified, takes the WS2812 gpio
+ # type:int (optional) = Type of LED, defaults to WS2812 RGB
+ # rmt:int (optional) = RMT hardware channel to use, leave default unless you have a good reason
+ def init(leds, gpio, type, rmt) # rmt is optional
+ self.gamma = true # gamma is enabled by default, it should be disabled explicitly if needed
+ self.leds = int(leds)
+
+ if gpio == nil && gpio.pin(gpio.WS2812) >= 0
+ gpio = gpio.pin(gpio.WS2812)
+ end
+
+ # if no GPIO, abort
+ if gpio == nil
+ raise "valuer_error", "no GPIO specified for neopixelbus"
+ end
+
+ # initialize the structure
+ self.ctor(self.leds, gpio, type, rmt)
+
+ if self._p == nil raise "internal_error", "couldn't not initialize noepixelbus" end
+
+ # call begin
+ self.begin()
+
+ end
+
+ def clear()
+ self.clear_to(0x000000)
+ self.show()
+ end
+
+ def ctor(leds, gpio, rmt)
+ if rmt == nil
+ self.call_native(0, leds, gpio)
+ else
+ self.call_native(0, leds, gpio, rmt)
+ end
+ end
+ def begin()
+ self.call_native(1)
+ end
+ def show()
+ self.call_native(2)
+ end
+ def can_show()
+ return self.call_native(3)
+ end
+ def is_dirty()
+ return self.call_native(4)
+ end
+ def dirty()
+ self.call_native(5)
+ end
+ def pixels_buffer()
+ return self.call_native(6)
+ end
+ def pixel_size()
+ return self.call_native(7)
+ end
+ def pixel_count()
+ return self.call_native(8)
+ end
+ def clear_to(col, bri)
+ self.call_native(9, self.to_gamma(col, bri))
+ end
+ def set_pixel_color(idx, col, bri)
+ self.call_native(10, idx, self.to_gamma(col, bri))
+ end
+ def get_pixel_color(idx)
+ return self.call_native(11, idx)
+ end
+ # def rotate_left(rot, first, last)
+ # self.call_native(20, rot, first, last)
+ # end
+ # def rotate_right(rot, first, last)
+ # self.call_native(21, rot, first, last)
+ # end
+ # def shift_left(rot, first, last)
+ # self.call_native(22, rot, first, last)
+ # end
+ # def shift_right(rot, first, last)
+ # self.call_native(22, rot, first, last)
+ # end
+
+ # apply gamma and bri
+ def to_gamma(rgbw, bri)
+ bri = (bri != nil) ? bri : 100
+ var r = tasmota.scale_uint(bri, 0, 100, 0, (rgbw & 0xFF0000) >> 16)
+ var g = tasmota.scale_uint(bri, 0, 100, 0, (rgbw & 0x00FF00) >> 8)
+ var b = tasmota.scale_uint(bri, 0, 100, 0, (rgbw & 0x0000FF))
+ if self.gamma
+ return light.gamma8(r) << 16 |
+ light.gamma8(g) << 8 |
+ light.gamma8(b)
+ else
+ return r << 16 |
+ g << 8 |
+ b
+ end
+ end
+
+ # `segment`
+ # create a new `strip` object that maps a part of the current strip
+ def create_segment(offset, leds)
+ if int(offset) + int(leds) > self.leds || offset < 0 || leds < 0
+ raise "value_error", "out of range"
+ end
+
+ # inner class
+ class Leds_segment
+ var strip
+ var offset, leds
+
+ def init(strip, offset, leds)
+ self.strip = strip
+ self.offset = int(offset)
+ self.leds = int(leds)
+ end
+
+ def clear()
+ self.clear_to(0x000000)
+ self.show()
+ end
+
+ def begin()
+ # do nothing, already being handled by physical strip
+ end
+ def show(force)
+ # don't trigger on segment, you will need to trigger on full strip instead
+ if bool(force) || (self.offset == 0 && self.leds == self.strip.leds)
+ self.strip.show()
+ end
+ end
+ def can_show()
+ return self.strip.can_show()
+ end
+ def is_dirty()
+ return self.strip.is_dirty()
+ end
+ def dirty()
+ self.strip.dirty()
+ end
+ def pixels_buffer()
+ return nil
+ end
+ def pixel_size()
+ return self.strip.pixel_size()
+ end
+ def pixel_count()
+ return self.leds
+ end
+ def clear_to(col, bri)
+ var i = 0
+ while i < self.leds
+ self.strip.set_pixel_color(i + self.offset, col, bri)
+ i += 1
+ end
+ end
+ def set_pixel_color(idx, col, bri)
+ self.strip.set_pixel_color(idx + self.offset, col, bri)
+ end
+ def get_pixel_color(idx)
+ return self.strip.get_pixel_color(idx + self.offseta)
+ end
+ end
+
+ return Leds_segment(self, offset, leds)
+
+ end
+
+ def create_matrix(w, h, offset)
+ offset = int(offset)
+ w = int(w)
+ h = int(h)
+ if offset == nil offset = 0 end
+ if w * h + offset > self.leds || h < 0 || w < 0 || offset < 0
+ raise "value_error", "out of range"
+ end
+
+ # inner class
+ class Leds_matrix
+ var strip
+ var offset
+ var h, w
+ var alternate # are rows in alternate mode (even/odd are reversed)
+
+ def init(strip, w, h, offset)
+ self.strip = strip
+ self.offset = offset
+ self.h = h
+ self.w = w
+ self.alternate = false
+ end
+
+ def clear()
+ self.clear_to(0x000000)
+ self.show()
+ end
+
+ def begin()
+ # do nothing, already being handled by physical strip
+ end
+ def show(force)
+ # don't trigger on segment, you will need to trigger on full strip instead
+ if bool(force) || (self.offset == 0 && self.w * self.h == self.strip.leds)
+ self.strip.show()
+ end
+ end
+ def can_show()
+ return self.strip.can_show()
+ end
+ def is_dirty()
+ return self.strip.is_dirty()
+ end
+ def dirty()
+ self.strip.dirty()
+ end
+ def pixels_buffer()
+ return nil
+ end
+ def pixel_size()
+ return self.strip.pixel_size()
+ end
+ def pixel_count()
+ return self.w * self.h
+ end
+ def clear_to(col, bri)
+ var i = 0
+ while i < self.w * self.h
+ self.strip.set_pixel_color(i + self.offset, col, bri)
+ i += 1
+ end
+ end
+ def set_pixel_color(idx, col, bri)
+ self.strip.set_pixel_color(idx + self.offset, col, bri)
+ end
+ def get_pixel_color(idx)
+ return self.strip.get_pixel_color(idx + self.offseta)
+ end
+
+ # Leds_matrix specific
+ def set_alternate(alt)
+ self.alternate = alt
+ end
+ def get_alternate()
+ return self.alternate
+ end
+
+ def set_matrix_pixel_color(x, y, col, bri)
+ if self.alternate && x % 2
+ # reversed line
+ self.strip.set_pixel_color(x * self.w + self.h - y - 1 + self.offset, col, bri)
+ else
+ self.strip.set_pixel_color(x * self.w + y + self.offset, col, bri)
+ end
+ end
+ end
+
+ return Leds_matrix(self, w, h, offset)
+
+ end
+
+ static def matrix(w, h, gpio, rmt)
+ var strip = Leds(w * h, gpio, rmt)
+ var matrix = strip.create_matrix(w, h, 0)
+ return matrix
+ end
+end
+
+
+#-
+
+var s = Leds(25, gpio.pin(gpio.WS2812, 1))
+s.clear_to(0x300000)
+s.show()
+i = 0
+
+def anim()
+ s.clear_to(0x300000)
+ s.set_pixel_color(i, 0x004000)
+ s.show()
+ i = (i + 1) % 25
+ tasmota.set_timer(200, anim)
+end
+anim()
+
+-#
+
+#-
+
+var s = Leds_matrix(5, 5, gpio.pin(gpio.WS2812, 1))
+s.set_alternate(true)
+s.clear_to(0x300000)
+s.show()
+x = 0
+y = 0
+
+def anim()
+ s.clear_to(0x300000)
+ s.set_matrix_pixel_color(x, y, 0x004000)
+ s.show()
+ y = (y + 1) % 5
+ if y == 0
+ x = (x + 1) % 5
+ end
+ tasmota.set_timer(200, anim)
+end
+anim()
+
+-#
diff --git a/lib/libesp32/berry/default/embedded/leds_animator.be b/lib/libesp32/berry/default/embedded/leds_animator.be
new file mode 100644
index 000000000..1ed25b491
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/leds_animator.be
@@ -0,0 +1,70 @@
+# class Leds_animator
+
+class Leds_animator
+ var strip # neopixelbus object
+ var pixel_count # number of pixels in the strip
+ var bri # brightness of the animation, 0..100, default 50
+ var running # is the animation running
+ var animators # animators list
+
+ def init(strip)
+ self.strip = strip
+ self.bri = 50 # percentage of brightness 0..100
+ self.running = false
+ self.pixel_count = strip.pixel_count()
+ self.animators = []
+ #
+ self.clear() # clear all leds first
+ #
+ tasmota.add_driver(self)
+ end
+
+ def add_anim(anim)
+ self.animators.push(anim)
+ anim.run() # start the animator
+ end
+
+ def clear()
+ self.stop()
+ self.strip.clear()
+ end
+ def start()
+ self.running = true
+ end
+ def stop()
+ self.running = false
+ end
+
+ def set_bri(bri)
+ self.bri = bri
+ end
+ def get_bri(bri)
+ return self.bri
+ end
+
+ def every_50ms()
+ if self.running
+ # run animators first
+ var i = 0
+ while i < size(self.animators)
+ var anim = self.animators[i]
+ if anim.is_running()
+ anim.animate()
+ i += 1
+ else
+ self.animators.remove(i) # remove any finished animator
+ end
+ end
+ # tirgger animate and display
+ self.animate()
+ end
+ end
+
+ def animate()
+ # placeholder - do nothing by default
+ end
+
+ def remove()
+ tasmota.remove_driver(self)
+ end
+end
diff --git a/lib/libesp32/berry/default/embedded/lv_clock_icon.be b/lib/libesp32/berry/default/embedded/lv_clock_icon.be
new file mode 100644
index 000000000..f5d19ca11
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/lv_clock_icon.be
@@ -0,0 +1,54 @@
+#- LVGL lv_clock_icon
+ -
+--#
+
+class lv_clock_icon: lv.label
+ var hour, minute, sec
+
+ def init(parent)
+ super(self).init(parent)
+ var f_s7_16 = lv.seg7_font(16)
+ if f_s7_16 != nil self.set_style_text_font(f_s7_16, lv.PART_MAIN | lv.STATE_DEFAULT) end
+
+ if parent != nil
+ var parent_height = parent.get_height()
+
+ self.set_text("--:--")
+ self.refr_size()
+ var w = self.get_width()
+ self.set_y((parent.get_height() - self.get_height()) / 2) # center vertically
+
+ var pad_right = parent.get_style_pad_right(lv.PART_MAIN | lv.STATE_DEFAULT)
+ self.set_x(parent.get_width() - w - pad_right - 3)
+ parent.set_style_pad_right(pad_right + w + 6, lv.PART_MAIN | lv.STATE_DEFAULT)
+
+ self.set_style_bg_color(lv.color(lv.COLOR_BLACK), lv.PART_MAIN | lv.STATE_DEFAULT)
+ end
+
+ tasmota.add_driver(self)
+ end
+
+ def set_time(hour, minute, sec)
+ import string
+ if hour != self.hour || minute != self.minute || sec != self.sec
+ var txt = string.format("%02d%s%02d", hour, sec % 2 ? ":" : " ", minute)
+ self.hour = hour
+ self.minute = minute
+ self.sec = sec
+ #if txt[0] == '0' txt = '!' .. string.split(txt,1)[1] end # replace first char with '!'
+ self.set_text(txt)
+ end
+ end
+
+ def every_second()
+ var now = tasmota.time_dump(tasmota.rtc()['local'])
+ if now['year'] != 1970
+ self.set_time(now['hour'], now['min'], now['sec'])
+ end
+ end
+
+ def del()
+ super(self).del()
+ tasmota.remove_driver(self)
+ end
+end
\ No newline at end of file
diff --git a/lib/libesp32/berry/default/embedded/lv_signal_arcs.be b/lib/libesp32/berry/default/embedded/lv_signal_arcs.be
new file mode 100644
index 000000000..7dd924e90
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/lv_signal_arcs.be
@@ -0,0 +1,133 @@
+#- LVGL lv_signal_bars and lv_wifi_bars
+ -
+--#
+
+class lv_signal_arcs : lv.obj
+ var percentage # value to display, range 0..100
+ var p1, p2, area, line_dsc # instances of objects kept to avoid re-instanciating at each call
+
+ def init(parent)
+ # init custom widget (don't call super constructor)
+ _lvgl.create_custom_widget(self, parent)
+ # own values
+ self.percentage = 100
+ # pre-allocate buffers
+ self.p1 = lv.point()
+ self.p2 = lv.point()
+ self.area = lv.area()
+ self.line_dsc = lv.draw_line_dsc()
+ end
+
+ def widget_event(cl, event)
+ # Call the ancestor's event handler
+ if lv.obj_event_base(cl, event) != lv.RES_OK return end
+ var code = event.code
+
+ import math
+ def atleast1(x) if x >= 1 return x else return 1 end end
+ # the model is that we have 4 bars and inter-bar (1/4 of width)
+ var height = self.get_height()
+ var width = self.get_width()
+
+ var inter_bar = atleast1(height / 8)
+ var bar = atleast1((height - inter_bar * 2) / 3)
+ var bar_offset = bar / 2
+ #print("inter_bar", inter_bar, "bar", bar, "bar_offset", bar_offset)
+
+ if code == lv.EVENT_DRAW_MAIN
+ var clip_area = lv.area(event.param)
+
+ # get coordinates of object
+ self.get_coords(self.area)
+ var x_ofs = self.area.x1
+ var y_ofs = self.area.y1
+
+ lv.draw_line_dsc_init(self.line_dsc) # initialize lv.draw_line_dsc structure
+ self.init_draw_line_dsc(lv.PART_MAIN, self.line_dsc) # copy the current values
+
+ self.line_dsc.round_start = 1
+ self.line_dsc.round_end = 1
+ self.line_dsc.width = (bar * 3 + 1) / 4
+ var on_color = self.get_style_line_color(lv.PART_MAIN | lv.STATE_DEFAULT)
+ var off_color = self.get_style_bg_color(lv.PART_MAIN | lv.STATE_DEFAULT)
+
+ # initial calculation, but does not take into account bounding box
+ # var angle = int(math.deg(math.atan2(width / 2, height)))
+
+ # better calculation
+ var hypotenuse = height - bar # center if at bar/2 from bottom and circle stops at bar/2 from top
+ var adjacent = width / 2 - bar_offset # stop at bar_offset from side
+ var angle = int(90 - math.deg(math.acos(real(adjacent) / real(hypotenuse))))
+ if (angle > 45) angle = 45 end
+
+ # print("hypotenuse",hypotenuse,"adjacent",adjacent,"angle",angle)
+ self.p1.x = x_ofs + width / 2
+ self.p1.y = y_ofs + height - 1 - bar_offset
+
+ self.line_dsc.color = self.percentage >= 25 ? on_color : off_color
+ lv.draw_arc(self.p1.x, self.p1.y, 0 * (bar + inter_bar) + bar_offset, 0, 360, clip_area, self.line_dsc)
+ self.line_dsc.color = self.percentage >= 50 ? on_color : off_color
+ lv.draw_arc(self.p1.x, self.p1.y, 1 * (bar + inter_bar) + bar_offset - 1, 270 - angle, 270 + angle, clip_area, self.line_dsc)
+ self.line_dsc.color = self.percentage >= 75 ? on_color : off_color
+ lv.draw_arc(self.p1.x, self.p1.y, 2 * (bar + inter_bar) + bar_offset - 2, 270 - angle, 270 + angle, clip_area, self.line_dsc)
+
+ #elif mode == lv.DESIGN_DRAW_POST # commented since we don't want a frame around this object
+ # self.ancestor_design.call(self, clip_area, mode)
+ end
+ end
+
+ def set_percentage(v)
+ var old_bars = self.percentage / 25
+ if v > 100 v = 100 end
+ if v < 0 v = 0 end
+ self.percentage = v
+ if old_bars != v / 25
+ self.invalidate() # be frugal and avoid updating the widget if it's not needed
+ end
+ end
+
+ def get_percentage()
+ return self.percentage
+ end
+end
+
+class lv_wifi_arcs: lv_signal_arcs
+ def init(parent)
+ super(self).init(parent)
+ tasmota.add_driver(self)
+ self.set_percentage(0) # we generally start with 0, meaning not connected
+ end
+
+ def every_second()
+ var wifi = tasmota.wifi()
+ var quality = wifi.find("quality")
+ var ip = wifi.find("ip")
+ if ip == nil
+ self.set_percentage(0)
+ elif quality != nil
+ self.set_percentage(quality)
+ end
+ end
+
+ def del()
+ super(self).del()
+ tasmota.remove_driver(self)
+ end
+end
+
+class lv_wifi_arcs_icon: lv_wifi_arcs
+ def init(parent)
+ super(self).init(parent)
+ self.set_style_line_color(lv.color(lv.COLOR_WHITE), lv.PART_MAIN | lv.STATE_DEFAULT)
+ self.set_style_bg_color(lv.color(lv.COLOR_BLACK), lv.PART_MAIN | lv.STATE_DEFAULT)
+ if parent != nil
+ var parent_height = parent.get_height()
+ var pad_right = parent.get_style_pad_right(lv.PART_MAIN | lv.STATE_DEFAULT)
+ self.set_height(parent_height)
+ var w = (parent_height*4)/3
+ self.set_width(w) # 130%
+ self.set_x(parent.get_width() - w - pad_right)
+ parent.set_style_pad_right(pad_right + w + 1, lv.PART_MAIN | lv.STATE_DEFAULT)
+ end
+ end
+end
\ No newline at end of file
diff --git a/lib/libesp32/berry/default/embedded/lv_signal_bars.be b/lib/libesp32/berry/default/embedded/lv_signal_bars.be
new file mode 100644
index 000000000..f548457b9
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/lv_signal_bars.be
@@ -0,0 +1,118 @@
+#- LVGL lv_signal_bars and lv_wifi_bars
+ -
+--#
+
+class lv_signal_bars : lv.obj
+ var percentage # value to display, range 0..100
+ var p1, p2, area, line_dsc # instances of objects kept to avoid re-instanciating at each call
+
+ def init(parent)
+ # init custom widget (don't call super constructor)
+ _lvgl.create_custom_widget(self, parent)
+ # own values
+ self.percentage = 100
+ # pre-allocate buffers
+ self.p1 = lv.point()
+ self.p2 = lv.point()
+ self.area = lv.area()
+ self.line_dsc = lv.draw_line_dsc()
+ end
+
+ def widget_event(cl, event)
+ # Call the ancestor's event handler
+ if lv.obj_event_base(cl, event) != lv.RES_OK return end
+ var code = event.code
+
+ def atleast1(x) if x >= 1 return x else return 1 end end
+ # the model is that we have 4 bars and inter-bar (1/4 of width)
+ var height = self.get_height()
+ var width = self.get_width()
+
+ var inter_bar = atleast1(width / 15)
+ var bar = atleast1((width - inter_bar * 3) / 4)
+ var bar_offset = bar / 2
+
+ if code == lv.EVENT_DRAW_MAIN
+ var clip_area = lv.area(event.param)
+
+ # get coordinates of object
+ self.get_coords(self.area)
+ var x_ofs = self.area.x1
+ var y_ofs = self.area.y1
+
+ lv.draw_line_dsc_init(self.line_dsc) # initialize lv_draw_line_dsc structure
+ self.init_draw_line_dsc(lv.PART_MAIN, self.line_dsc) # copy the current values
+
+ self.line_dsc.round_start = 1
+ self.line_dsc.round_end = 1
+ self.line_dsc.width = bar
+ var on_color = self.get_style_line_color(lv.PART_MAIN | lv.STATE_DEFAULT)
+ var off_color = self.get_style_bg_color(lv.PART_MAIN | lv.STATE_DEFAULT)
+
+ lv.event_send(self, lv.EVENT_DRAW_PART_BEGIN, self.line_dsc)
+ for i:0..3 # 4 bars
+ self.line_dsc.color = self.percentage >= (i+1)*20 ? on_color : off_color
+ self.p1.y = y_ofs + height - 1 - bar_offset
+ self.p1.x = x_ofs + i * (bar + inter_bar) + bar_offset
+ self.p2.y = y_ofs + ((3 - i) * (height - bar)) / 4 + bar_offset
+ self.p2.x = self.p1.x
+ lv.draw_line(self.p1, self.p2, clip_area, self.line_dsc)
+ end
+ lv.event_send(self, lv.EVENT_DRAW_PART_END, self.line_dsc)
+ end
+ end
+
+ def set_percentage(v)
+ var old_bars = self.percentage / 20
+ if v > 100 v = 100 end
+ if v < 0 v = 0 end
+ self.percentage = v
+ if old_bars != v / 20
+ self.invalidate() # be frugal and avoid updating the widget if it's not needed
+ end
+ end
+
+ def get_percentage()
+ return self.percentage
+ end
+end
+
+class lv_wifi_bars: lv_signal_bars
+ def init(parent)
+ super(self).init(parent)
+ tasmota.add_driver(self)
+ self.set_percentage(0) # we generally start with 0, meaning not connected
+ end
+
+ def every_second()
+ var wifi = tasmota.wifi()
+ var quality = wifi.find("quality")
+ var ip = wifi.find("ip")
+ if ip == nil
+ self.set_percentage(0)
+ elif quality != nil
+ self.set_percentage(quality)
+ end
+ end
+
+ def del()
+ super(self).del()
+ tasmota.remove_driver(self)
+ end
+end
+
+class lv_wifi_bars_icon: lv_wifi_bars
+ def init(parent)
+ super(self).init(parent)
+ self.set_style_line_color(lv.color(lv.COLOR_WHITE), lv.PART_MAIN | lv.STATE_DEFAULT)
+ self.set_style_bg_color(lv.color(lv.COLOR_BLACK), lv.PART_MAIN | lv.STATE_DEFAULT)
+ if parent != nil
+ var parent_height = parent.get_height()
+ var pad_right = parent.get_style_pad_right(lv.PART_MAIN | lv.STATE_DEFAULT)
+ self.set_height(parent_height)
+ self.set_width(parent_height)
+ self.set_x(parent.get_width() - parent_height - pad_right)
+ parent.set_style_pad_right(pad_right + parent_height + 1, lv.PART_MAIN | lv.STATE_DEFAULT)
+ end
+ end
+end
diff --git a/lib/libesp32/berry/default/embedded/lvgl_glob.be b/lib/libesp32/berry/default/embedded/lvgl_glob.be
new file mode 100644
index 000000000..04250ff54
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/lvgl_glob.be
@@ -0,0 +1,256 @@
+#- embedded class for LVGL globals -#
+
+#- This class stores all globals used by LVGL and cannot be stored in the solidified module -#
+#- this limits the globals to a single value '_lvgl' -#
+class LVGL_glob
+ # all variables are lazily initialized to reduce the memory pressure. Until they are used, they consume zero memory
+ var cb_obj # map between a native C pointer (as int) and the corresponding lv.lv_* berry object, also helps marking the objects as non-gc-able
+ var cb_event_closure # mapping for event closures per LVGL native pointer (int)
+ var event_cb # native callback for lv.lv_event
+
+ #- below are native callbacks mapped to a closure to a method of this instance -#
+ var null_cb # cb called if type is not supported
+ var widget_ctor_cb
+ var widget_dtor_cb
+ var widget_event_cb
+
+ var widget_struct_default
+ var widget_struct_by_class
+
+ #- this is the fallback callback, if the event is unknown or unsupported -#
+ static cb_do_nothing = def() print("LVG: call to unsupported callback") end
+
+ #- register an lv.lv_* object in the mapping -#
+ def register_obj(obj)
+ if self.cb_obj == nil self.cb_obj = {} end
+ self.cb_obj[obj._p] = obj
+ end
+
+ def get_object_from_ptr(ptr)
+ if self.cb_obj != nil
+ return self.cb_obj.find(ptr) # raise an exception if something is wrong
+ end
+ end
+
+ def lvgl_event_dispatch(event_ptr)
+ import introspect
+
+ var event = lv.lv_event(introspect.toptr(event_ptr))
+
+ var target = event.target
+ var f = self.cb_event_closure[target]
+ var obj = self.get_object_from_ptr(target)
+ #print('>> lvgl_event_dispatch', f, obj, event)
+ f(obj, event)
+ end
+
+ def gen_cb(name, f, obj, ptr)
+ #print('>> gen_cb', name, obj, ptr)
+ # record the object, whatever the callback
+
+ if name == "lv_event_cb"
+ if self.cb_event_closure == nil self.cb_event_closure = {} end
+ if self.event_cb == nil self.event_cb = tasmota.gen_cb(/ event_ptr -> self.lvgl_event_dispatch(event_ptr)) end # encapsulate 'self' in closure
+
+ self.register_obj(obj)
+ self.cb_event_closure[ptr] = f
+ return self.event_cb
+ # elif name == ""
+ else
+ if self.null_cb == nil self.null_cb = tasmota.gen_cb(self.cb_do_nothing) end
+ return self.null_cb
+ end
+ end
+
+ def widget_ctor_impl(cl_ptr, obj_ptr)
+ import introspect
+ var cl = lv.lv_obj_class(cl_ptr)
+ var obj = self.get_object_from_ptr(obj_ptr)
+ if self.cb_obj.find(obj) obj = self.cb_obj[obj] end
+ # print("widget_ctor_impl", cl, obj)
+ if type(obj) == 'instance' && introspect.get(obj, 'widget_constructor')
+ obj.widget_constructor(cl)
+ end
+ end
+ def widget_dtor_impl(cl_ptr, obj_ptr)
+ import introspect
+ var cl = lv.lv_obj_class(cl_ptr)
+ var obj = self.get_object_from_ptr(obj_ptr)
+ # print("widget_dtor_impl", cl, obj)
+ if type(obj) == 'instance' && introspect.get(obj, 'widget_destructor')
+ obj.widget_destructor(cl)
+ end
+ end
+ def widget_event_impl(cl_ptr, e_ptr)
+ import introspect
+ var cl = lv.lv_obj_class(cl_ptr)
+ var event = lv.lv_event(e_ptr)
+ var obj_ptr = event.target
+ var obj = self.get_object_from_ptr(obj_ptr)
+ if type(obj) == 'instance' && introspect.get(obj, 'widget_event')
+ obj.widget_event(cl, event)
+ end
+ # print("widget_event_impl", cl, obj_ptr, obj, event)
+ end
+
+
+ def widget_cb()
+ if self.widget_ctor_cb == nil self.widget_ctor_cb = tasmota.gen_cb(/ cl, obj -> self.widget_ctor_impl(cl, obj)) end
+ if self.widget_dtor_cb == nil self.widget_dtor_cb = tasmota.gen_cb(/ cl, obj -> self.widget_dtor_impl(cl, obj)) end
+ if self.widget_event_cb == nil self.widget_event_cb = tasmota.gen_cb(/ cl, e -> self.widget_event_impl(cl, e)) end
+
+ if self.widget_struct_default == nil
+ self.widget_struct_default = lv.lv_obj_class(lv.lv_obj._class).copy()
+ self.widget_struct_default.base_class = lv.lv_obj._class # by default, inherit from base class `lv_obj`, this can be overriden
+ self.widget_struct_default.constructor_cb = self.widget_ctor_cb # set the berry cb dispatchers
+ self.widget_struct_default.destructor_cb = self.widget_dtor_cb
+ self.widget_struct_default.event_cb = self.widget_event_cb
+ end
+ end
+
+ #- deregister_obj all information linked to a specific LVGL native object (int) -#
+ def deregister_obj(obj)
+ if self.cb_obj != nil self.cb_obj.remove(obj) end
+ if self.cb_event_closure != nil self.cb_event_closure.remove(obj) end
+ end
+
+ #- initialize a custom widget -#
+ #- arg must be a subclass of lv.lv_obj -#
+ def create_custom_widget(obj, parent)
+ import introspect
+
+ if !isinstance(obj, lv.lv_obj) raise "value_error", "arg must be a subclass of lv_obj" end
+ if self.widget_struct_by_class == nil self.widget_struct_by_class = {} end
+
+ var obj_classname = classname(obj)
+ var obj_class_struct = self.widget_struct_by_class.find(obj_classname)
+ # print("classname=",obj_classname,"_class",super(obj)._class)
+ #- not already built, create a new one for this class -#
+ if obj_class_struct == nil
+ self.widget_cb() # set up all structures
+ obj_class_struct = self.widget_struct_default.copy() # get a copy of the structure with pre-defined callbacks
+ obj_class_struct.base_class = super(obj)._class
+ if introspect.get(obj, 'widget_width_def') obj_class_struct.width_def = obj.widget_width_def end
+ if introspect.get(obj, 'widget_height_def') obj_class_struct.height_def = obj.widget_height_def end
+ if introspect.get(obj, 'widget_editable') obj_class_struct.editable = obj.widget_editable end
+ if introspect.get(obj, 'widget_group_def') obj_class_struct.group_def = obj.widget_group_def end
+ if introspect.get(obj, 'widget_instance_size') obj_class_struct.instance_size = obj.widget_instance_size end
+
+ #- keep a copy of the structure to avoid GC and reuse if needed -#
+ self.widget_struct_by_class[obj_classname] = obj_class_struct
+ end
+
+ var lv_obj_ptr = lv.obj_class_create_obj(obj_class_struct, parent)
+ obj._p = lv_obj_ptr._p
+ self.register_obj(obj)
+ obj.class_init_obj()
+ end
+end
+
+_lvgl = LVGL_glob()
+
+# class lv_custom_widget : lv.lv_obj
+# # static widget_width_def
+# # static widget_height_def
+# # static widget_editable
+# # static widget_group_def
+# # static widget_instance_size
+# #
+# var percentage # value to display, range 0..100
+# var p1, p2, area, line_dsc # instances of objects kept to avoid re-instanciating at each call
+
+# def init(parent)
+# _lvgl.create_custom_widget(self, parent)
+# # own values
+# self.percentage = 100
+# # pre-allocate buffers
+# self.p1 = lv.lv_point()
+# self.p2 = lv.lv_point()
+# self.area = lv.lv_area()
+# self.line_dsc = lv.lv_draw_line_dsc()
+# end
+
+# # def widget_constructor(cl)
+# # print("widget_constructor", cl)
+# # end
+
+# # def widget_destructor(cl)
+# # print("widget_destructor", cl)
+# # end
+
+# def widget_event(cl, event)
+# var res = lv.obj_event_base(cl, event)
+# if res != lv.RES_OK return end
+
+# def atleast1(x) if x >= 1 return x else return 1 end end
+# # the model is that we have 4 bars and inter-bar (1/4 of width)
+# var height = self.get_height()
+# var width = self.get_width()
+
+# var inter_bar = atleast1(width / 15)
+# var bar = atleast1((width - inter_bar * 3) / 4)
+# var bar_offset = bar / 2
+
+# var code = event.code
+# if code == lv.EVENT_DRAW_MAIN
+# var clip_area = lv.lv_area(event.param)
+# print("widget_event DRAW", clip_area.tomap())
+# # lv.event_send(self, lv.EVENT_DRAW_MAIN, clip_area)
+
+# # get coordinates of object
+# self.get_coords(self.area)
+# var x_ofs = self.area.x1
+# var y_ofs = self.area.y1
+
+# lv.draw_line_dsc_init(self.line_dsc) # initialize lv.lv_draw_line_dsc structure
+# self.init_draw_line_dsc(lv.PART_MAIN, self.line_dsc)
+
+# self.line_dsc.round_start = 1
+# self.line_dsc.round_end = 1
+# self.line_dsc.width = bar
+
+# var on_color = self.get_style_line_color(lv.PART_MAIN | lv.STATE_DEFAULT)
+# var off_color = self.get_style_bg_color(lv.PART_MAIN | lv.STATE_DEFAULT)
+
+# lv.event_send(self, lv.EVENT_DRAW_PART_BEGIN, self.line_dsc)
+# for i:0..3 # 4 bars
+# self.line_dsc.color = self.percentage >= (i+1)*20 ? on_color : off_color
+# self.p1.y = y_ofs + height - 1 - bar_offset
+# self.p1.x = x_ofs + i * (bar + inter_bar) + bar_offset
+# self.p2.y = y_ofs + ((3 - i) * (height - bar)) / 4 + bar_offset
+# self.p2.x = self.p1.x
+# lv.draw_line(self.p1, self.p2, clip_area, self.line_dsc)
+# end
+# lv.event_send(self, lv.EVENT_DRAW_PART_END, self.line_dsc)
+
+# end
+# end
+
+# def set_percentage(v)
+# var old_bars = self.percentage / 5
+# if v > 100 v = 100 end
+# if v < 0 v = 0 end
+# self.percentage = v
+# if old_bars != v / 5
+# self.invalidate() # be frugal and avoid updating the widget if it's not needed
+# end
+# end
+
+# def get_percentage()
+# return self.percentage
+# end
+# end
+
+# ########## ########## ########## ########## ########## ########## ########## ##########
+
+# lv.start()
+
+# hres = lv.get_hor_res() # should be 320
+# vres = lv.get_ver_res() # should be 240
+
+# scr = lv.scr_act() # default screean object
+# f20 = lv.montserrat_font(20) # load embedded Montserrat 20
+
+# scr.set_style_bg_color(lv.lv_color(0x0000A0), lv.PART_MAIN | lv.STATE_DEFAULT)
+
+# w = lv_custom_widget(scr)
\ No newline at end of file
diff --git a/lib/libesp32/berry/default/embedded/openhasp.be b/lib/libesp32/berry/default/embedded/openhasp.be
new file mode 100644
index 000000000..4232a605b
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/openhasp.be
@@ -0,0 +1,764 @@
+import string
+import json
+
+# lv.start()
+# scr = lv.scr_act() # default screean object
+# scr.set_style_bg_color(lv.color(0x0000A0), lv.PART_MAIN | lv.STATE_DEFAULT)
+
+lv.start()
+
+hres = lv.get_hor_res() # should be 320
+vres = lv.get_ver_res() # should be 240
+
+scr = lv.scr_act() # default screean object
+#f20 = lv.montserrat_font(20) # load embedded Montserrat 20
+r20 = lv.font_robotocondensed_latin1(20)
+r16 = lv.font_robotocondensed_latin1(16)
+
+th2 = lv.theme_openhasp_init(0, lv.color(0xFF00FF), lv.color(0x303030), false, r16)
+scr.get_disp().set_theme(th2)
+# TODO
+scr.set_style_bg_color(lv.color(lv.COLOR_WHITE),0)
+
+# apply theme to layer_top, but keep it transparent
+lv.theme_apply(lv.layer_top())
+lv.layer_top().set_style_bg_opa(0,0)
+
+
+# takes an attribute name and responds if it needs color conversion
+def is_color_attribute(t)
+ import string
+ t = str(t)
+ # contains `color` but does not contain `color_`
+ return (string.find(t, "color") >= 0) && (string.find(t, "color_") < 0)
+end
+
+# parse hex string
+def parse_hex(s)
+ import string
+ s = string.toupper(s) # turn to uppercase
+ var val = 0
+ for i:0..size(s)-1
+ var c = s[i]
+ # var c_int = string.byte(c)
+ if c == "#" continue end # skip '#' prefix if any
+ if c == "x" || c == "X" continue end # skip 'x' or 'X'
+
+ if c >= "A" && c <= "F"
+ val = (val << 4) | string.byte(c) - 55
+ elif c >= "0" && c <= "9"
+ val = (val << 4) | string.byte(c) - 48
+ end
+ end
+ return val
+end
+
+def parse_color(s)
+ s = str(s)
+ if s[0] == '#'
+ return lv.color(parse_hex(s))
+ else
+ import string
+ import introspect
+ var col_name = "COLOR_" + string.toupper(s)
+ var col_try = introspect.get(lv, col_name)
+ if col_try != nil
+ return lv.color(col_try)
+ end
+ end
+ # fail safe with black color
+ return lv.color(0x000000)
+end
+
+#- ------------------------------------------------------------
+ Class `lvh_obj` encapsulating `lv_obj``
+
+ Provide a mapping for virtual members
+ Stores the associated page and object id
+
+ Adds specific virtual members used by OpenHASP
+- ------------------------------------------------------------ -#
+class lvh_obj
+ # _lv_class refers to the lvgl class encapsulated, and is overriden by subclasses
+ static _lv_class = lv.obj
+ static _lv_part2_selector # selector for secondary part (like knob of arc)
+
+ # attributes to ignore when set at object level (they are managed by page)
+ static _attr_ignore = [
+ "id",
+ "obj",
+ "page",
+ "comment",
+ "parentid",
+ "auto_size", # TODO not sure it's still needed in LVGL8
+ ]
+ #- mapping from OpenHASP attribute to LVGL attribute -#
+ #- if mapping is null, we use set_X and get_X from our own class -#
+ static _attr_map = {
+ "x": "x",
+ "y": "y",
+ "w": "width",
+ "h": "height",
+ # arc
+ "asjustable": nil,
+ "mode": nil,
+ "start_angle": "bg_start_angle",
+ "start_angle1": "start_angle",
+ "end_angle": "bg_end_angle",
+ "end_angle1": "end_angle",
+ "radius": "style_radius",
+ "border_side": "style_border_side",
+ "bg_opa": "style_bg_opa",
+ "border_width": "style_border_width",
+ "line_width": nil, # depebds on class
+ "line_width1": nil, # depebds on class
+ "action": nil, # store the action in self._action
+ "hidden": nil, # apply to self
+ "enabled": nil, # apply to self
+ "click": nil, # synonym to enabled
+ "toggle": nil,
+ "bg_color": "style_bg_color",
+ "bg_grad_color": "style_bg_grad_color",
+ "type": nil,
+ # below automatically create a sub-label
+ "text": nil, # apply to self
+ "value_str": nil, # synonym to 'text'
+ "align": nil,
+ "text_font": nil,
+ "value_font": nil, # synonym to text_font
+ "text_color": nil,
+ "value_color": nil, # synonym to text_color
+ "value_ofs_x": nil,
+ "value_ofs_y": nil,
+ #
+ "min": nil,
+ "max": nil,
+ "val": "value",
+ "rotation": "rotation",
+ # img
+ "src": "src",
+ "image_recolor": "style_img_recolor",
+ "image_recolor_opa": "style_img_recolor_opa",
+ # spinner
+ "angle": nil,
+ "speed": nil,
+ # padding of knob
+ "pad_top2": nil,
+ "pad_bottom2": nil,
+ "pad_left2": nil,
+ "pad_right2": nil,
+ "pad_all2": nil,
+ "radius2": nil,
+ }
+
+ var _lv_obj # native lvgl object
+ var _lv_label # sub-label if exists
+ var _action # action for OpenHASP
+
+ # init
+ # - create the LVGL encapsulated object
+ # arg1: parent object
+ # arg2: json line object
+ def init(parent, jline)
+ var obj_class = self._lv_class # need to assign to a var to distinguish from method call
+ self._lv_obj = obj_class(parent) # instanciate LVGL object
+ self.post_init()
+ end
+
+ # post-init, to be overriden
+ def post_init()
+ end
+
+ # get LVGL encapsulated object
+ def get_obj()
+ return self._lv_obj
+ end
+
+ def set_action(t)
+ self._action = str(t)
+ end
+ def get_action()
+ return self._action()
+ end
+
+ def set_line_width(t)
+ self._lv_obj.set_style_line_width(int(t), lv.PART_MAIN | lv.STATE_DEFAULT)
+ end
+ def get_line_width()
+ return self._lv_obj.get_style_line_width(lv.PART_MAIN | lv.STATE_DEFAULT)
+ end
+
+ #- ------------------------------------------------------------
+ Mapping of synthetic attributes
+ - text
+ - hidden
+ - enabled
+ - ------------------------------------------------------------ -#
+ #- `hidden` attributes mapped to OBJ_FLAG_HIDDEN -#
+ def set_hidden(h)
+ if h
+ self._lv_obj.add_flag(lv.OBJ_FLAG_HIDDEN)
+ else
+ self._lv_obj.clear_flag(lv.OBJ_FLAG_HIDDEN)
+ end
+ end
+
+ def get_hidden()
+ return self._lv_obj.has_flag(lv.OBJ_FLAG_HIDDEN)
+ end
+
+ #- `enabled` attributes mapped to OBJ_FLAG_CLICKABLE -#
+ def set_enabled(h)
+ if h
+ self._lv_obj.add_flag(lv.OBJ_FLAG_CLICKABLE)
+ else
+ self._lv_obj.clear_flag(lv.OBJ_FLAG_CLICKABLE)
+ end
+ end
+
+ def get_enabled()
+ return self._lv_obj.has_flag(lv.OBJ_FLAG_CLICKABLE)
+ end
+ # click is synonym to enabled
+ def set_click(t) self.set_enabled(t) end
+ def get_click() return self.get_enabled() end
+
+ #- `toggle` attributes mapped to STATE_CHECKED -#
+ def set_toggle(t)
+ if t == "TRUE" t = true end
+ if t == "FALSE" t = false end
+ if t
+ self._lv_obj.add_state(lv.STATE_CHECKED)
+ else
+ self._lv_obj.clear_state(lv.STATE_CHECKED)
+ end
+ end
+
+ def get_toggle()
+ return self._lv_obj.has_state(lv.STATE_CHECKED)
+ end
+
+ def set_adjustable(t)
+ if t
+ self._lv_obj.add_flag(lv.OBJ_FLAG_CLICKABLE)
+ else
+ self._lv_obj.clear_flag(lv.OBJ_FLAG_CLICKABLE)
+ end
+ end
+ def get_adjustable()
+ return self._lv_obj.has_flag(lv.OBJ_FLAG_CLICKABLE)
+ end
+
+ #- set_text: create a `lv_label` sub object to the current object -#
+ #- (default case, may be overriden by object that directly take text) -#
+ def check_label()
+ if self._lv_label == nil
+ self._lv_label = lv.label(self.get_obj())
+ self._lv_label.set_align(lv.ALIGN_CENTER);
+ end
+ end
+
+ def set_text(t)
+ self.check_label()
+ self._lv_label.set_text(str(t))
+ end
+ def set_value_str(t) self.set_text(t) end
+
+ def get_text()
+ if self._lv_label == nil return nil end
+ return self._lv_label.get_text()
+ end
+ def get_value_str() return self.get_text() end
+
+ def set_align(t)
+ var align
+ self.check_label()
+ if t == 0 || t == "left"
+ align = lv.TEXT_ALIGN_LEFT
+ elif t == 1 || t == "center"
+ align = lv.TEXT_ALIGN_CENTER
+ elif t == 2 || t == "right"
+ align = lv.TEXT_ALIGN_RIGHT
+ end
+ self._lv_label.set_style_text_align(align, lv.PART_MAIN | lv.STATE_DEFAULT)
+ end
+
+ def get_align()
+ if self._lv_label == nil return nil end
+ var align self._lv_label.get_style_text_align(lv.PART_MAIN | lv.STATE_DEFAULT)
+ if align == lv.TEXT_ALIGN_LEFT
+ return "left"
+ elif align == lv.TEXT_ALIGN_CENTER
+ return "center"
+ elif align == lv.TEXT_ALIGN_RIGHT
+ return "right"
+ else
+ return nil
+ end
+ end
+
+ def set_text_font(t)
+ self.check_label()
+ var f = lv.font_robotocondensed_latin1(int(t))
+ if f != nil
+ self._lv_label.set_style_text_font(f, lv.PART_MAIN | lv.STATE_DEFAULT)
+ else
+ print("HSP: Unsupported font size: robotocondensed-latin1", t)
+ end
+ end
+ def get_text_font()
+ end
+ def set_value_font(t) self.set_text_font(t) end
+ def get_value_font() return self.get_text_font() end
+
+ def set_text_color(t)
+ self.check_label()
+ self._lv_label.set_style_text_color(parse_color(t), lv.PART_MAIN | lv.STATE_DEFAULT)
+ end
+ def get_text_color()
+ return self._text_color
+ end
+ def set_value_color(t) self.set_text_color(t) end
+ def get_value_color() return self.get_value_color() end
+
+ def set_value_ofs_x(t)
+ self.check_label()
+ self._lv_label.set_x(int(t))
+ end
+ def get_value_ofs_x()
+ return self._lv_label.get_x()
+ end
+ def set_value_ofs_y(t)
+ self.check_label()
+ self._lv_label.set_y(int(t))
+ end
+ def get_value_ofs_y()
+ return self._lv_label.get_y()
+ end
+
+ # secondary element
+ def set_pad_top2(t)
+ if self._lv_part2_selector != nil
+ self._lv_obj.set_style_pad_top(int(t), self._lv_part2_selector | lv.STATE_DEFAULT)
+ end
+ end
+ def set_pad_bottom2(t)
+ if self._lv_part2_selector != nil
+ self._lv_obj.set_style_pad_bottom(int(t), self._lv_part2_selector | lv.STATE_DEFAULT)
+ end
+ end
+ def set_pad_left2(t)
+ if self._lv_part2_selector != nil
+ self._lv_obj.set_style_pad_left(int(t), self._lv_part2_selector | lv.STATE_DEFAULT)
+ end
+ end
+ def set_pad_right2(t)
+ if self._lv_part2_selector != nil
+ self._lv_obj.set_style_pad_right(int(t), self._lv_part2_selector | lv.STATE_DEFAULT)
+ end
+ end
+ def set_pad_all2(t)
+ if self._lv_part2_selector != nil
+ self._lv_obj.set_style_pad_all(int(t), self._lv_part2_selector | lv.STATE_DEFAULT)
+ end
+ end
+
+ def get_pad_top()
+ if self._lv_part2_selector != nil
+ return self._lv_obj.get_style_pad_top(self._lv_part2_selector | lv.STATE_DEFAULT)
+ end
+ end
+ def get_pad_bottomo()
+ if self._lv_part2_selector != nil
+ return self._lv_obj.get_style_pad_bottom(self._lv_part2_selector | lv.STATE_DEFAULT)
+ end
+ end
+ def get_pad_left()
+ if self._lv_part2_selector != nil
+ return self._lv_obj.get_style_pad_left(self._lv_part2_selector | lv.STATE_DEFAULT)
+ end
+ end
+ def get_pad_right()
+ if self._lv_part2_selector != nil
+ return self._lv_obj.get_style_pad_right(self._lv_part2_selector | lv.STATE_DEFAULT)
+ end
+ end
+ def get_pad_all()
+ end
+
+ def set_radius2(t)
+ if self._lv_part2_selector != nil
+ self._lv_obj.set_style_radius(int(t), self._lv_part2_selector | lv.STATE_DEFAULT)
+ end
+ end
+ def get_radius2()
+ if self._lv_part2_selector != nil
+ return self._lv_obj.get_style_radius(self._lv_part2_selector | lv.STATE_DEFAULT)
+ end
+ end
+
+ #- ------------------------------------------------------------
+ Mapping of virtual attributes
+ - ------------------------------------------------------------ -#
+ def member(k)
+ # tostring is a special case, we shouldn't raise an exception for it
+ if k == 'tostring' return nil end
+ #
+ if self._attr_map.has(k)
+ import introspect
+ var kv = self._attr_map[k]
+ if kv
+ var f = introspect.get(self._lv_obj, "get_" + kv)
+ if type(f) == 'function'
+ return f(self._lv_obj)
+ end
+ else
+ # call self method
+ var f = introspect.get(self, "get_" + k)
+ if type(f) == 'function'
+ return f(self, k)
+ end
+ end
+ end
+ raise "value_error", "unknown attribute " + str(k)
+ end
+
+ def setmember(k, v)
+ import string
+ # print(">> setmember", k, v)
+ # print(">>", classname(self), self._attr_map)
+ if self._attr_ignore.find(k) != nil
+ return
+ elif self._attr_map.has(k)
+ import introspect
+ var kv = self._attr_map[k]
+ if kv
+ var f = introspect.get(self._lv_obj, "set_" + kv)
+ # if the attribute contains 'color', convert to lv_color
+ if type(kv) == 'string' && is_color_attribute(kv)
+ v = parse_color(v)
+ end
+ # print("f=", f, v, kv, self._lv_obj, self)
+ if type(f) == 'function'
+ if string.find(kv, "style_") == 0
+ # style function need a selector as second parameter
+ f(self._lv_obj, v, lv.PART_MAIN | lv.STATE_DEFAULT)
+ else
+ f(self._lv_obj, v)
+ end
+ return
+ else
+ print("HSP: Could not find function set_"+kv)
+ end
+ else
+ # call self method
+ var f = introspect.get(self, "set_" + k)
+ # print("f==",f)
+ if type(f) == 'function'
+ f(self, v)
+ return
+ end
+ end
+
+ else
+ print("HSP: unknown attribute:", k)
+ end
+ # silently ignore if the attribute name is not supported
+ end
+end
+
+#- ------------------------------------------------------------
+ Other widgets
+- ------------------------------------------------------------ -#
+
+#- ------------------------------------------------------------
+ label
+#- ------------------------------------------------------------#
+class lvh_label : lvh_obj
+ static _lv_class = lv.label
+ # label do not need a sub-label
+ def post_init()
+ self._lv_label = self._lv_obj
+ end
+end
+
+#- ------------------------------------------------------------
+ arc
+#- ------------------------------------------------------------#
+class lvh_arc : lvh_obj
+ static _lv_class = lv.arc
+ static _lv_part2_selector = lv.PART_KNOB
+
+ # line_width converts to arc_width
+ def set_line_width(t)
+ self._lv_obj.set_style_arc_width(int(t), lv.PART_MAIN | lv.STATE_DEFAULT)
+ end
+ def get_line_width()
+ return self._lv_obj.get_arc_line_width(lv.PART_MAIN | lv.STATE_DEFAULT)
+ end
+ def set_line_width1(t)
+ self._lv_obj.set_style_arc_width(int(t), lv.PART_INDICATOR | lv.STATE_DEFAULT)
+ end
+ def get_line_width1()
+ return self._lv_obj.get_arc_line_width(lv.PART_INDICATOR | lv.STATE_DEFAULT)
+ end
+
+ def set_min(t)
+ self._lv_obj.set_range(int(t), self.get_max())
+ end
+ def set_max(t)
+ self._lv_obj.set_range(self.get_min(), int(t))
+ end
+ def get_min()
+ return self._lv_obj.get_min_value()
+ end
+ def get_max()
+ return self._lv_obj.get_max_value()
+ end
+ def set_type(t)
+ var mode
+ if t == 0 mode = lv.ARC_MODE_NORMAL
+ elif t == 1 mode = lv.ARC_MODE_REVERSE
+ elif t == 2 mode = lv.ARC_MODE_SYMMETRICAL
+ end
+ if mode != nil
+ self._lv_obj.set_mode(mode)
+ end
+ end
+ def get_type()
+ return self._lv_obj.get_mode()
+ end
+ # mode
+ def set_mode(t)
+ var mode
+ if mode == "expand" self._lv_obj.set_width(lv.SIZE_CONTENT)
+ elif mode == "break" mode = lv.LABEL_LONG_WRAP
+ elif mode == "dots" mode = lv.LABEL_LONG_DOT
+ elif mode == "scroll" mode = lv.LABEL_LONG_SCROLL
+ elif mode == "loop" mode = lv.LABEL_LONG_SCROLL_CIRCULAR
+ elif mode == "crop" mode = lv.LABEL_LONG_CLIP
+ end
+ if mode != nil
+ self._lv_obj.lv_label_set_long_mode(mode)
+ end
+ end
+ def get_mode()
+ end
+
+end
+
+#- ------------------------------------------------------------
+ switch
+#- ------------------------------------------------------------#
+class lvh_switch : lvh_obj
+ static _lv_class = lv.switch
+ static _lv_part2_selector = lv.PART_KNOB
+end
+
+#- ------------------------------------------------------------
+ spinner
+#- ------------------------------------------------------------#
+class lvh_spinner : lvh_arc
+ static _lv_class = lv.spinner
+
+ # init
+ # - create the LVGL encapsulated object
+ # arg1: parent object
+ # arg2: json line object
+ def init(parent, jline)
+ var angle = jline.find("angle", 60)
+ var speed = jline.find("speed", 1000)
+ self._lv_obj = lv.spinner(parent, speed, angle)
+ self.post_init()
+ end
+
+ # ignore attributes, spinner can't be changed once created
+ def set_angle(t) end
+ def get_angle() end
+ def set_speed(t) end
+ def get_speed() end
+end
+
+#- creat sub-classes of lvh_obj and map the LVGL class in static '_lv_class' attribute -#
+class lvh_bar : lvh_obj static _lv_class = lv.bar end
+class lvh_btn : lvh_obj static _lv_class = lv.btn end
+class lvh_btnmatrix : lvh_obj static _lv_class = lv.btnmatrix end
+class lvh_checkbox : lvh_obj static _lv_class = lv.checkbox end
+class lvh_dropdown : lvh_obj static _lv_class = lv.dropdown end
+class lvh_img : lvh_obj static _lv_class = lv.img end
+class lvh_line : lvh_obj static _lv_class = lv.line end
+class lvh_roller : lvh_obj static _lv_class = lv.roller end
+class lvh_slider : lvh_obj static _lv_class = lv.slider end
+class lvh_textarea : lvh_obj static _lv_class = lv.textarea end
+
+#- ----------------------------------------------------------------------------
+ Class `lvh_page` encapsulating `lv_obj` as screen (created with lv.obj(0))
+- ----------------------------------------------------------------------------- -#
+# ex of transition: lv.scr_load_anim(scr, lv.SCR_LOAD_ANIM_MOVE_RIGHT, 500, 0, false)
+class lvh_page
+ var _obj_id # (map) of objects by id numbers
+ var _page_id # (int) id number of the page
+ var _lv_scr # (lv_obj) lvgl screen object
+
+ #- init(page_number) -#
+ def init(page_number)
+ import global
+
+ # if no parameter, default to page #1
+ if page_number == nil page_number = 1 end
+
+ self._page_id = page_number # remember our page_number
+ self._obj_id = {} # init list of objects
+ if page_number == 1
+ self._lv_scr = lv.scr_act() # default screen
+ elif page_number == 0
+ self._lv_scr = lv.layer_top() # top layer, visible over all screens
+ else
+ self._lv_scr = lv.obj(0) # allocate a new screen
+ # self._lv_scr.set_style_bg_color(lv.color(0x000000), lv.PART_MAIN | lv.STATE_DEFAULT) # set black background
+ self._lv_scr.set_style_bg_color(lv.color(0xFFFFFF), lv.PART_MAIN | lv.STATE_DEFAULT) # set white background
+ end
+
+ # create a global for this page of form p, ex p1
+ var glob_name = string.format("p%i", self._page_id)
+ global.(glob_name) = self
+ end
+
+ #- retrieve lvgl screen object for this page -#
+ def get_scr()
+ return self._lv_scr
+ end
+
+ #- add an object to this page -#
+ def set_obj(id, o)
+ self._obj_id[id] = o
+ end
+ def get_obj(id)
+ return self._obj_id.find(id)
+ end
+
+ #- return id of this page -#
+ def id()
+ return self._page_id
+ end
+
+ #- show this page, with animation -#
+ def show(anim, duration)
+ # ignore if there is no screen, like for id 0
+ if self._lv_scr == nil return nil end
+ # ignore if the screen is already active
+ if self._lv_scr._p == lv.scr_act()._p return end # do nothing
+
+ # default animation is lv.SCR_LOAD_ANIM_MOVE_RIGHT
+ if anim == nil anim = lv.SCR_LOAD_ANIM_MOVE_RIGHT end
+ # default duration of 500ms
+ if duration == nil duration = 500 end
+
+ # load new screen with anumation, no delay, 500ms transition time, no auto-delete
+ lv.scr_load_anim(self._lv_scr, lv.SCR_LOAD_ANIM_MOVE_RIGHT, duration, 0, false)
+ end
+end
+
+#- pages -#
+var lvh_page_cur = lvh_page(1)
+var lvh_pages = { 1: lvh_page_cur } # always create page #1
+
+f = open("pages.jsonl","r")
+var jsonl = string.split(f.read(), "\n")
+f.close()
+
+#- ------------------------------------------------------------
+ Parse page information
+
+ Create a new page object if required
+ Change the active page
+- ------------------------------------------------------------ -#
+def parse_page(jline)
+ if jline.has("page") && type(jline["page"]) == 'int'
+ var page = int(jline["page"])
+ # does the page already exist?
+ if lvh_pages.has(page)
+ # yes, just change the current page
+ lvh_page_cur = lvh_pages[page]
+ else
+ # no, create a new page
+ lvh_page_cur = lvh_page(page)
+ lvh_pages[page] = lvh_page_cur
+ end
+ end
+end
+
+#- ------------------------------------------------------------
+ Parse single object
+
+- ------------------------------------------------------------ -#
+def parse_obj(jline, page)
+ import global
+ import introspect
+
+ # line must contain 'obj' and 'id', otherwise it is ignored
+ if jline.has("obj") && jline.has("id") && type(jline["id"]) == 'int'
+ # 'obj_id' must be between 1 and 254
+ var obj_id = int(jline["id"])
+ if obj_id < 1 || obj_id > 254
+ raise "value error", "invalid id " + str(obj_id)
+ end
+
+ # extract openhasp class, prefix with `lvh_`. Ex: `btn` becomes `lvh_btn`
+ var obj_type = jline["obj"]
+
+ # extract parent
+ var parent
+ var parent_id = int(jline.find("parentid"))
+ if parent_id != nil
+ var parent_obj = lvh_page_cur.get_obj(parent_id)
+ if parent_obj != nil
+ parent = parent_obj._lv_obj
+ end
+ end
+ if parent == nil
+ parent = page.get_scr()
+ end
+
+ # check if a class with the requested name exists
+ var obj_class = introspect.get(global, "lvh_" + obj_type)
+ if obj_class == nil
+ raise "value error", "cannot find object of type " + str(obj_type)
+ end
+
+ # instanciate the object, passing the lvgl screen as paren object
+ var obj = obj_class(parent, jline)
+
+ # add object to page object
+ lvh_page_cur.set_obj(obj_id, obj)
+ # set attributes
+ # try every attribute, if not supported it is silently ignored
+ for k:jline.keys()
+ # introspect.set(obj, k, jline[k])
+ obj.(k) = jline[k]
+ end
+
+ # create a global variable for this object of form pb, ex p1b2
+ var glob_name = string.format("p%ib%i", lvh_page_cur.id(), obj_id)
+ global.(glob_name) = obj
+ end
+end
+
+# ex:
+# {'page': 1, 'h': 50, 'obj': 'label', 'hidden': false, 'text': 'Hello', 'x': 5, 'id': 1, 'enabled': true, 'y': 5, 'w': 50}
+# {"page":1,"id":2,"obj":"btn","x":5,"y":90,"h":90,"w":50,"text":"World","enabled":false,"hidden":false}
+
+#- ------------------------------------------------------------
+ Parse jsonl file line by line
+
+- ------------------------------------------------------------ -#
+tasmota.yield()
+for j:jsonl
+ var jline = json.load(j)
+
+ # parse page first
+ if type(jline) == 'instance'
+ parse_page(jline)
+ parse_obj(jline, lvh_page_cur)
+ end
+end
diff --git a/lib/libesp32/berry/default/embedded/openhasp/demo-all.jsonl b/lib/libesp32/berry/default/embedded/openhasp/demo-all.jsonl
new file mode 100644
index 000000000..76d3ed810
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/openhasp/demo-all.jsonl
@@ -0,0 +1,61 @@
+{"page":1,"comment":"---------- Page 1 ----------"}
+{"page":1,"id":0,"bg_color":"#FFFFFF","bg_grad_color":"#FFFFFF","text_color":"#000000","radius":0,"border_side":0}
+{"page":1,"id":1,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"LIVING ROOM","value_font":24,"bg_color":"#2C3E50","bg_grad_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0}
+
+{"page":1,"id":2,"obj":"arc","x":20,"y":65,"w":80,"h":100,"max":40,"border_side":0,"type":0,"rotation":0,"start_angle":180,"end_angle":0,"start_angle1":180,"value_font":12,"value_ofs_x":0,"value_ofs_y":-14,"bg_opa":0,"text":"21.2°C","min":-20,"max":50,"val":21}
+
+{"page":1,"id":3,"obj":"arc","x":140,"y":65,"w":80,"h":100,"max":100,"border_side":0,"type":0,"start_angle":180,"end_angle":0,"start_angle1":180,"value_font":12,"value_color":"#000000","value_ofs_x":0,"value_ofs_y":-14,"bg_opa":0,"text":"44%","val":44}
+
+{"page":1,"id":4,"obj":"label","x":0,"y":120,"w":240,"h":20,"text":"CO2 levels: 1483 ppm","radius":0,"border_side":0,"align":1}
+{"page":1,"id":5,"obj":"label","x":2,"y":35,"w":140,"text":"Temperature","align":1}
+{"page":1,"id":6,"obj":"label","x":140,"y":35,"w":95,"text":"Humidity","align":1}
+{"page":1,"id":7,"obj":"btn","x":0,"y":160,"w":240,"h":20,"text":"LIGHTS","bg_color":"#F1C40F","text_color":"#FFFFFF","radius":0,"border_side":0}
+{"page":1,"id":8,"obj":"label","x":20,"y":190,"w":140,"h":20,"text":"Ceiling Light"}
+{"page":1,"id":9,"obj":"switch","x":160,"y":190,"w":40,"h":20,"toggle":"TRUE"}
+{"page":1,"id":10,"obj":"label","x":20,"y":215,"w":140,"h":20,"text":"Wall Light"}
+{"page":1,"id":11,"obj":"switch","x":160,"y":215,"w":40,"h":20,"toggle":"TRUE"}
+{"page":1,"id":12,"obj":"label","x":20,"y":240,"w":200,"h":20,"text":"Ambient Light"}
+{"page":1,"id":13,"obj":"slider","x":30,"y":265,"w":200,"h":10}
+
+{"page":2,"comment":"---------- Page 2 ----------"}
+{"page":2,"id":1,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"ENTITIES","value_font":24,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0,"click":0}
+{"page":2,"id":2,"obj":"obj","x":5,"y":35,"w":230,"h":250,"click":0}
+
+{"page":2,"id":11,"obj":"label","x":8,"y":33,"w":35,"h":35,"text":"\uE004","align":1,"text_font":32,"text_color":"black"}
+{"page":2,"id":12,"obj":"label","x":48,"y":43,"w":130,"h":30,"text":"Presence override","align":0,"text_font":16,"text_color":"black"}
+{"page":2,"id":13,"obj":"switch","x":177,"y":40,"w":50,"h":25,"radius":25,"radius2":15}
+
+{"page":2,"id":21,"obj":"label","x":8,"y":69,"w":35,"h":35,"text":"\uF020","align":1,"text_font":32,"text_color":"black"}
+{"page":2,"id":22,"obj":"label","x":48,"y":79,"w":130,"h":30,"text":"Front door light","align":0,"text_font":16,"text_color":"black"}
+{"page":2,"id":23,"obj":"switch","x":177,"y":74,"w":50,"h":25,"radius":25,"radius2":15}
+
+{"page":2,"id":31,"obj":"label","x":8,"y":103,"w":35,"h":35,"text":"\uF054","align":1,"text_font":32,"text_color":"black"}
+{"page":2,"id":32,"obj":"label","x":48,"y":113,"w":130,"h":30,"text":"Back yard lights","align":0,"text_font":16,"text_color":"black"}
+{"page":2,"id":33,"obj":"switch","x":177,"y":110,"w":50,"h":25,"radius":25,"radius2":15}
+
+{"page":2,"id":41,"obj":"label","x":8,"y":138,"w":35,"h":35,"text":"\uEA7A","align":1,"text_font":32,"text_color":"black"}
+{"page":2,"id":42,"obj":"label","x":48,"y":148,"w":130,"h":30,"text":"Trash service","align":0,"text_font":16,"text_color":"black"}
+{"page":2,"id":43,"obj":"label","x":97,"y":148,"w":130,"h":30,"text":"in 6 days","align":2,"text_color":"black"}
+
+{"page":2,"id":51,"obj":"label","x":8,"y":173,"w":35,"h":35,"text":"\uF39D","align":1,"text_font":32,"text_color":"black"}
+{"page":2,"id":52,"obj":"label","x":48,"y":183,"w":130,"h":30,"text":"Selective trash","align":0,"text_font":16,"text_color":"black"}
+{"page":2,"id":53,"obj":"label","x":97,"y":183,"w":130,"h":30,"text":"in 10 days","align":2,"text_color":"black"}
+
+{"page":2,"id":61,"obj":"label","x":8,"y":208,"w":35,"h":35,"text":"\uE32A","align":1,"text_font":32,"text_color":"black"}
+{"page":2,"id":62,"obj":"label","x":48,"y":218,"w":130,"h":30,"text":"Green energy active","align":0,"text_font":16,"text_color":"black"}
+{"page":2,"id":63,"obj":"label","x":97,"y":218,"w":130,"h":30,"text":"Yes :)","align":2,"text_color":"black"}
+
+{"page":2,"id":71,"obj":"label","x":8,"y":243,"w":35,"h":35,"text":"\uE957","align":1,"text_font":32,"text_color":"black"}
+{"page":2,"id":72,"obj":"label","x":48,"y":253,"w":130,"h":30,"text":"Air quality","align":0,"text_font":16,"text_color":"black"}
+{"page":2,"id":73,"obj":"label","x":97,"y":253,"w":130,"h":30,"text":"OK (29.58 µg/m³)","align":2,"text_color":"black"}
+
+{"page":3,"comment":"---------- Page 3 ----------"}
+{"page":3,"id":1,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"FAN STATUS","text_font":16,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0,"click":0}
+
+{"page":3,"id":11,"obj":"img","src":"A:/noun_Fan_35097_140.png","auto_size":1,"w":140,"h":140,"x":50,"y":75,"image_recolor":"lime","image_recolor_opa":150}
+{"page":3,"id":12,"obj":"spinner","parentid":11,"x":7,"y":6,"w":126,"h":126,"bg_opa":0,"border_width":0,"line_width":7,"line_width1":7,"type":2,"angle":120,"speed":1000,"value_str":3,"value_font":24}
+
+{"page":0,"comment":"---------- All pages ----------"}
+{"page":0,"id":11,"obj":"btn","action":"prev","x":0,"y":290,"w":79,"h":32,"bg_color":"#34495E","text":"\uE141","text_color":"#CCCCCC","radius":0,"border_side":0,"text_font":32}
+{"page":0,"id":12,"obj":"btn","action":"back","x":80,"y":290,"w":80,"h":32,"bg_color":"#34495E","text":"\uE2DC","text_color":"#CCCCCC","radius":0,"border_side":0,"text_font":24}
+{"page":0,"id":13,"obj":"btn","action":"next","x":161,"y":290,"w":79,"h":32,"bg_color":"#34495E","text":"\uE142","text_color":"#CCCCCC","radius":0,"border_side":0,"text_font":32}
diff --git a/lib/libesp32/berry/default/embedded/openhasp/demo1.jsonl b/lib/libesp32/berry/default/embedded/openhasp/demo1.jsonl
new file mode 100644
index 000000000..684e0d324
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/openhasp/demo1.jsonl
@@ -0,0 +1,23 @@
+{"page":1,"comment":"---------- Page 1 ----------"}
+{"page":1,"id":0,"bg_color":"#FFFFFF","bg_grad_color":"#FFFFFF","text_color":"#000000","radius":0,"border_side":0}
+{"page":1,"id":1,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"LIVING ROOM","value_font":22,"bg_color":"#2C3E50","bg_grad_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0}
+
+{"page":1,"id":2,"obj":"arc","x":20,"y":65,"w":80,"h":100,"max":40,"border_side":0,"type":0,"rotation":0,"start_angle":180,"end_angle":0,"start_angle1":180,"value_font":12,"value_ofs_x":0,"value_ofs_y":-14,"bg_opa":0,"text":"21.2°C","min":-20,"max":50,"val":21}
+
+{"page":1,"id":3,"obj":"arc","x":140,"y":65,"w":80,"h":100,"max":100,"border_side":0,"type":0,"start_angle":180,"end_angle":0,"start_angle1":180,"value_font":12,"value_color":"#000000","value_ofs_x":0,"value_ofs_y":-14,"bg_opa":0,"text":"44%","val":44}
+
+{"page":1,"id":4,"obj":"label","x":0,"y":120,"w":240,"h":20,"text":"CO2 levels: 1483 ppm","radius":0,"border_side":0,"align":1}
+{"page":1,"id":5,"obj":"label","x":2,"y":35,"w":140,"text":"Temperature","align":1}
+{"page":1,"id":6,"obj":"label","x":140,"y":35,"w":95,"text":"Humidity","align":1}
+{"page":1,"id":7,"obj":"btn","x":0,"y":160,"w":240,"h":20,"text":"LIGHTS","bg_color":"#F1C40F","text_color":"#FFFFFF","radius":0,"border_side":0}
+{"page":1,"id":8,"obj":"label","x":20,"y":190,"w":140,"h":20,"text":"Ceiling Light"}
+{"page":1,"id":9,"obj":"switch","x":160,"y":190,"w":40,"h":20,"toggle":"TRUE"}
+{"page":1,"id":10,"obj":"label","x":20,"y":215,"w":140,"h":20,"text":"Wall Light"}
+{"page":1,"id":11,"obj":"switch","x":160,"y":215,"w":40,"h":20,"toggle":"TRUE"}
+{"page":1,"id":12,"obj":"label","x":20,"y":240,"w":200,"h":20,"text":"Ambient Light"}
+{"page":1,"id":13,"obj":"slider","x":30,"y":265,"w":200,"h":10}
+
+{"page":0,"comment":"---------- All pages ----------"}
+{"page":0,"id":11,"obj":"btn","action":"prev","x":0,"y":290,"w":79,"h":32,"bg_color":"#34495E","text":"\uE141","text_color":"#CCCCCC","radius":0,"border_side":0,"text_font":32}
+{"page":0,"id":12,"obj":"btn","action":"back","x":80,"y":290,"w":80,"h":32,"bg_color":"#34495E","text":"\uE2DC","text_color":"#CCCCCC","radius":0,"border_side":0,"text_font":24}
+{"page":0,"id":13,"obj":"btn","action":"next","x":161,"y":290,"w":79,"h":32,"bg_color":"#34495E","text":"\uE142","text_color":"#CCCCCC","radius":0,"border_side":0,"text_font":32}
diff --git a/lib/libesp32/berry/default/embedded/openhasp/demo2.jsonl b/lib/libesp32/berry/default/embedded/openhasp/demo2.jsonl
new file mode 100644
index 000000000..b1d6efc34
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/openhasp/demo2.jsonl
@@ -0,0 +1,35 @@
+{"page":1,"id":1,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"ENTITIES","value_font":22,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0,"click":0}
+{"page":1,"id":2,"obj":"obj","x":5,"y":35,"w":230,"h":250,"click":0}
+
+{"page":1,"id":11,"obj":"label","x":8,"y":33,"w":35,"h":35,"text":"\uE004","align":1,"text_font":32,"text_color":"black"}
+{"page":1,"id":12,"obj":"label","x":48,"y":43,"w":130,"h":30,"text":"Presence override","align":0,"text_font":16,"text_color":"black"}
+{"page":1,"id":13,"obj":"switch","x":177,"y":40,"w":50,"h":25,"radius":25,"radius2":15}
+
+{"page":1,"id":21,"obj":"label","x":8,"y":69,"w":35,"h":35,"text":"\uF020","align":1,"text_font":32,"text_color":"black"}
+{"page":1,"id":22,"obj":"label","x":48,"y":79,"w":130,"h":30,"text":"Front door light","align":0,"text_font":16,"text_color":"black"}
+{"page":1,"id":23,"obj":"switch","x":177,"y":74,"w":50,"h":25,"radius":25,"radius2":15}
+
+{"page":1,"id":31,"obj":"label","x":8,"y":103,"w":35,"h":35,"text":"\uF054","align":1,"text_font":32,"text_color":"black"}
+{"page":1,"id":32,"obj":"label","x":48,"y":113,"w":130,"h":30,"text":"Back yard lights","align":0,"text_font":16,"text_color":"black"}
+{"page":1,"id":33,"obj":"switch","x":177,"y":110,"w":50,"h":25,"radius":25,"radius2":15}
+
+{"page":1,"id":41,"obj":"label","x":8,"y":138,"w":35,"h":35,"text":"\uEA7A","align":1,"text_font":32,"text_color":"black"}
+{"page":1,"id":42,"obj":"label","x":48,"y":148,"w":130,"h":30,"text":"Trash service","align":0,"text_font":16,"text_color":"black"}
+{"page":1,"id":43,"obj":"label","x":97,"y":148,"w":130,"h":30,"text":"in 6 days","align":2,"text_color":"black"}
+
+{"page":1,"id":51,"obj":"label","x":8,"y":173,"w":35,"h":35,"text":"\uF39D","align":1,"text_font":32,"text_color":"black"}
+{"page":1,"id":52,"obj":"label","x":48,"y":183,"w":130,"h":30,"text":"Selective trash","align":0,"text_font":16,"text_color":"black"}
+{"page":1,"id":53,"obj":"label","x":97,"y":183,"w":130,"h":30,"text":"in 10 days","align":2,"text_color":"black"}
+
+{"page":1,"id":61,"obj":"label","x":8,"y":208,"w":35,"h":35,"text":"\uE32A","align":1,"text_font":32,"text_color":"black"}
+{"page":1,"id":62,"obj":"label","x":48,"y":218,"w":130,"h":30,"text":"Green energy active","align":0,"text_font":16,"text_color":"black"}
+{"page":1,"id":63,"obj":"label","x":97,"y":218,"w":130,"h":30,"text":"Yes :)","align":2,"text_color":"black"}
+
+{"page":1,"id":71,"obj":"label","x":8,"y":243,"w":35,"h":35,"text":"\uE957","align":1,"text_font":32,"text_color":"black"}
+{"page":1,"id":72,"obj":"label","x":48,"y":253,"w":130,"h":30,"text":"Air quality","align":0,"text_font":16,"text_color":"black"}
+{"page":1,"id":73,"obj":"label","x":97,"y":253,"w":130,"h":30,"text":"OK (29.58 µg/m³)","align":2,"text_color":"black"}
+
+{"page":0,"comment":"---------- All pages ----------"}
+{"page":0,"id":11,"obj":"btn","action":"prev","x":0,"y":290,"w":79,"h":32,"bg_color":"#34495E","text":"\uE141","text_color":"#CCCCCC","radius":0,"border_side":0,"text_font":32}
+{"page":0,"id":12,"obj":"btn","action":"back","x":80,"y":290,"w":80,"h":32,"bg_color":"#34495E","text":"\uE2DC","text_color":"#CCCCCC","radius":0,"border_side":0,"text_font":24}
+{"page":0,"id":13,"obj":"btn","action":"next","x":161,"y":290,"w":79,"h":32,"bg_color":"#34495E","text":"\uE142","text_color":"#CCCCCC","radius":0,"border_side":0,"text_font":32}
diff --git a/lib/libesp32/berry/default/embedded/openhasp/demo3.jsonl b/lib/libesp32/berry/default/embedded/openhasp/demo3.jsonl
new file mode 100644
index 000000000..f8b952f81
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/openhasp/demo3.jsonl
@@ -0,0 +1,4 @@
+{"page":1,"id":1,"obj":"btn","x":0,"y":0,"w":240,"h":30,"text":"FAN STATUS","text_font":16,"bg_color":"#2C3E50","text_color":"#FFFFFF","radius":0,"border_side":0,"click":0}
+
+{"page":1,"id":11,"obj":"img","src":"A:/noun_Fan_35097_140.png","auto_size":1,"w":140,"h":140,"x":50,"y":75,"image_recolor":"lime","image_recolor_opa":150}
+{"page":1,"id":12,"obj":"spinner","parentid":11,"x":7,"y":6,"w":126,"h":126,"bg_opa":0,"border_width":0,"line_width":7,"line_width1":7,"type":2,"angle":120,"speed":1000,"value_str":3,"value_font":24}
\ No newline at end of file
diff --git a/lib/libesp32/berry/default/embedded/persist.be b/lib/libesp32/berry/default/embedded/persist.be
new file mode 100644
index 000000000..164a1dd7b
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/persist.be
@@ -0,0 +1,161 @@
+#- persistance module for Berry -#
+#- -#
+#- To solidify: -#
+#-
+ # load only persis_module and persist_module.init
+ import solidify
+ solidify.dump(persist_module.init)
+ # copy and paste into `be_persist_lib.c`
+-#
+var persist_module = module("persist")
+
+persist_module.init = def (m)
+
+ class Persist
+ var _filename
+ var _p
+ var _dirty
+
+ #- persist can be initialized with pre-existing values. The map is not copied so any change will be reflected -#
+ def init(m)
+ # print("Persist init")
+ self._filename = '_persist.json'
+ if isinstance(m,map)
+ self._p = m.copy() # need to copy instead?
+ else
+ self._p = {}
+ end
+ self.load(self._p, self._filename)
+ self._dirty = false
+ # print("Persist init")
+ end
+
+ #- virtual member getter, if a key does not exists return `nil`-#
+ def member(key)
+ return self._p.find(key)
+ end
+
+ #- virtual member setter -#
+ def setmember(key, value)
+ self._p[key] = value
+ self._dirty = true
+ end
+
+ #- clear all entries -#
+ def zero()
+ self._p = {}
+ self._dirty = true
+ end
+
+ def remove(k)
+ self._p.remove(k)
+ self._dirty = true
+ end
+
+ def has(k)
+ return self._p.has(k)
+ end
+
+ def find(k, d)
+ return self._p.find(k, d)
+ end
+
+ def load()
+ import json
+ import path
+ var f # file object
+ var val # values loaded from json
+
+ if path.exists(self._filename)
+ try
+ f = open(self._filename, "r")
+ val = json.load(f.read())
+ f.close()
+ except .. as e, m
+ if f != nil f.close() end
+ raise e, m
+ end
+ if isinstance(val, map)
+ self._p = val # sucess
+ else
+ print("BRY: failed to load _persist.json")
+ end
+ self._dirty = false
+ else
+ self.save()
+ end
+
+ # print("Loading")
+ end
+
+ def save()
+ var f # file object
+ try
+ f = open(self._filename, "w")
+ self.json_fdump(f)
+ f.close()
+ except .. as e, m
+ if f != nil f.close() end
+ f = open(self._filename, "w")
+ f.write('{}') # fallback write empty map
+ f.close()
+ raise e, m
+ end
+ self._dirty = false
+ # print("Saving")
+ end
+
+ def json_fdump_any(f, v)
+ import json
+ if isinstance(v, map)
+ self.json_fdump_map(f, v)
+ elif isinstance(v, list)v
+ self.json_fdump_list(f, v)
+ else
+ f.write(json.dump(v))
+ end
+ end
+
+ def json_fdump_map(f, v)
+ import json
+ f.write('{')
+ var sep = nil
+ for k:v.keys()
+ if sep != nil f.write(sep) end
+
+ f.write(json.dump(str(k)))
+ f.write(':')
+ self.json_fdump_any(f, v[k])
+
+ sep = ","
+ end
+ f.write('}')
+ end
+
+ def json_fdump_list(f, v)
+ import json
+ f.write('[')
+ var i = 0
+ while i < size(v)
+ if i > 0 f.write(',') end
+ self.json_fdump_any(f, v[i])
+ i += 1
+ end
+ f.write(']')
+ end
+
+ def json_fdump(f)
+ import json
+ if isinstance(self._p, map)
+ self.json_fdump_map(f, self._p)
+ else
+ raise "internal_error", "persist._p is not a map"
+ end
+ end
+ end
+
+
+ return Persist() # return an instance of this class
+end
+
+return persist_module
diff --git a/lib/libesp32/berry/default/embedded/tapp.be b/lib/libesp32/berry/default/embedded/tapp.be
new file mode 100644
index 000000000..30aa1f740
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/tapp.be
@@ -0,0 +1,35 @@
+#- Tasmota apps module for Berry -#
+#- -#
+
+var tapp_module = module("tapp")
+
+tapp_module.init = def (m)
+
+ class Tapp
+
+ def init()
+ tasmota.add_driver(self)
+ end
+
+ def autoexec()
+ import path
+ import string
+
+ var dir = path.listdir("/")
+
+ for d: dir
+ if string.find(d, ".tapp") > 0
+ tasmota.log(string.format("TAP: found Tasmota App '%s'", d), 2)
+ tasmota.load(d + "#autoexec.be")
+ end
+ end
+ end
+ end
+
+ return Tapp() # return an instance of this class
+end
+
+# aa = autoconf_module.init(autoconf_module)
+# import webserver
+# webserver.on('/ac2', / -> aa.page_autoconf_mgr(), webserver.HTTP_GET)
+return tapp_module
diff --git a/lib/libesp32/berry/default/embedded/test_crypto.be b/lib/libesp32/berry/default/embedded/test_crypto.be
new file mode 100644
index 000000000..f2edbfee5
--- /dev/null
+++ b/lib/libesp32/berry/default/embedded/test_crypto.be
@@ -0,0 +1,30 @@
+ec = crypto.EC_C25519()
+
+# Alice
+sk_A = bytes('77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a')
+pk_A = ec.public_key(sk_A)
+assert(pk_A == bytes('8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a'))
+
+# Bob
+sk_B = bytes('5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb')
+pk_B = ec.public_key(sk_B)
+assert(pk_B == bytes('de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f'))
+
+psk = ec.shared_key(sk_A, pk_B)
+assert(psk == bytes('4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742'))
+psk2 = ec.shared_key(sk_B, pk_A)
+assert(psk2 == bytes('4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742'))
+
+#- test vectors from RFC77748
+
+ Alice's private key, a:
+ 77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a
+ Alice's public key, X25519(a, 9):
+ 8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a
+ Bob's private key, b:
+ 5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb
+ Bob's public key, X25519(b, 9):
+ de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f
+ Their shared secret, K:
+ 4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742
+-#
diff --git a/lib/libesp32/berry/default/static_block.hpp b/lib/libesp32/berry/default/static_block.hpp
new file mode 100644
index 000000000..152dda130
--- /dev/null
+++ b/lib/libesp32/berry/default/static_block.hpp
@@ -0,0 +1,80 @@
+/**
+ * static_block.hpp
+ *
+ * An implementation of a Java-style static block, in C++ (and potentially a
+ * GCC/clang extension to avoid warnings). Almost, but not quite, valid C.
+ * Partially inspired by Andrei Alexandrescu's Scope Guard and
+ * discussions on stackoverflow.com
+ *
+ * By Eyal Rozenberg
+ *
+ * Licensed under the Apache License v2.0:
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+#pragma once
+#ifndef STATIC_BLOCK_HPP_
+#define STATIC_BLOCK_HPP_
+
+#ifndef CONCATENATE
+#define CONCATENATE(s1, s2) s1##s2
+#define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)
+#endif /* CONCATENATE */
+
+#ifndef UNIQUE_IDENTIFIER
+/**
+ * This macro expands into a different identifier in every expansion.
+ * Note that you _can_ clash with an invocation of UNIQUE_IDENTIFIER
+ * by manually using the same identifier elsewhere; or by carefully
+ * choosing another prefix etc.
+ */
+#ifdef __COUNTER__
+#define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __COUNTER__)
+#else
+#define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __LINE__)
+#endif /* COUNTER */
+#else
+#endif /* UNIQUE_IDENTIFIER */
+
+/**
+ * Following is a mechanism for executing code statically.
+ *
+ * @note Caveats:
+ * - Your static block must be surround by curly braces.
+ * - No need for a semicolon after the block (but it won't hurt).
+ * - Do not put static blocks in files, as it might get compiled multiple
+ * times ane execute multiple times.
+ * - A static_block can only be used in file scope - not within any other block etc.
+ * - Templated static blocks will probably not work. Avoid them.
+ * - No other funny business, this is fragile.
+ * - This does not having any threading issues (AFAICT) - as it has no static
+ * initialization order issue. Of course, you have to _keep_ it safe with
+ * your static code.
+ * - Execution of the code is guaranteed to occur before main() executes,
+ * but the relative order of statics being initialized is unknown/unclear. So,
+ * do not call any method of an instance of a class which you expect to have been
+ * constructed; it may not have been. Instead, you can use a static getInstance() method
+ * (look this idiom up on the web, it's safe).
+ * - Variables defined within the static block are not global; they will
+ * go out of scope as soon as its execution concludes.
+ *
+ * Usage example:
+ *
+ * static_block {
+ * do_stuff();
+ * std::cout << "in the static block!\n";
+ * }
+ *
+ */
+#define static_block STATIC_BLOCK_IMPL1(UNIQUE_IDENTIFIER(_static_block_))
+
+#define STATIC_BLOCK_IMPL1(prefix) \
+ STATIC_BLOCK_IMPL2(CONCATENATE(prefix,_fn),CONCATENATE(prefix,_var))
+
+#define STATIC_BLOCK_IMPL2(function_name,var_name) \
+static void function_name(); \
+static int var_name __attribute((unused)) = (function_name(), 0) ; \
+static void function_name()
+
+
+#endif // STATIC_BLOCK_HPP_
diff --git a/lib/libesp32/berry/examples/anon_func.be b/lib/libesp32/berry/examples/anon_func.be
new file mode 100644
index 000000000..78854ce64
--- /dev/null
+++ b/lib/libesp32/berry/examples/anon_func.be
@@ -0,0 +1,20 @@
+# anonymous function and closure
+def count(x)
+ var arr = []
+ for i : 0 .. x
+ arr.push(
+ def (n) # loop variable cannot be used directly as free variable
+ return def ()
+ return n * n
+ end
+ end (i) # define and call anonymous function
+ )
+ end
+ return arr
+end
+
+for xx : count(6)
+ print(xx()) # 0, 1, 4 ... n * n
+end
+
+return count
diff --git a/lib/libesp32/berry/examples/bigloop.be b/lib/libesp32/berry/examples/bigloop.be
new file mode 100644
index 000000000..a3a77768b
--- /dev/null
+++ b/lib/libesp32/berry/examples/bigloop.be
@@ -0,0 +1,15 @@
+import time
+
+c = time.clock()
+do
+ i = 0
+ while i < 100000000
+ i += 1
+ end
+end
+print('while iteration 100000000 times', time.clock() - c, 's')
+
+c = time.clock()
+for i : 1 .. 100000000
+end
+print('for iteration 100000000 times', time.clock() - c, 's')
diff --git a/lib/libesp32/berry/examples/bintree.be b/lib/libesp32/berry/examples/bintree.be
new file mode 100644
index 000000000..81936f8a0
--- /dev/null
+++ b/lib/libesp32/berry/examples/bintree.be
@@ -0,0 +1,60 @@
+# Reference from https://github.com/BerryMathDevelopmentTeam/BerryMath/blob/master/testscript/BinaryTree.bm
+
+class node
+ var v, l, r
+ def init(v, l, r)
+ self.v = v
+ self.l = l
+ self.r = r
+ end
+ def insert(v)
+ if v < self.v
+ if self.l
+ self.l.insert(v)
+ else
+ self.l = node(v)
+ end
+ else
+ if self.r
+ self.r.insert(v)
+ else
+ self.r = node (v)
+ end
+ end
+ end
+ def sort(l)
+ if (self.l) self.l.sort(l) end
+ l.push(self.v)
+ if (self.r) self.r.sort(l) end
+ end
+end
+
+class btree
+ var root
+ def insert(v)
+ if self.root
+ self.root.insert(v)
+ else
+ self.root = node(v)
+ end
+ end
+ def sort()
+ var l = []
+ if self.root
+ self.root.sort(l)
+ end
+ return l
+ end
+end
+
+var tree = btree()
+tree.insert(-100)
+tree.insert(5);
+tree.insert(3);
+tree.insert(9);
+tree.insert(10);
+tree.insert(10000000);
+tree.insert(1);
+tree.insert(-1);
+tree.insert(-10);
+print(tree.sort());
diff --git a/lib/libesp32/berry/examples/calcpi.be b/lib/libesp32/berry/examples/calcpi.be
new file mode 100644
index 000000000..053f87875
--- /dev/null
+++ b/lib/libesp32/berry/examples/calcpi.be
@@ -0,0 +1,16 @@
+def cpi(n)
+ i = 2
+ pi = 3
+ while i <= n
+ term = 4.0 / (i * (i + 1) * (i + 2))
+ if i % 4
+ pi = pi + term
+ else
+ pi = pi - term
+ end
+ i = i + 2
+ end
+ return pi
+end
+
+print("pi =", cpi(100))
diff --git a/lib/libesp32/berry/examples/exception.be b/lib/libesp32/berry/examples/exception.be
new file mode 100644
index 000000000..3a3098dce
--- /dev/null
+++ b/lib/libesp32/berry/examples/exception.be
@@ -0,0 +1,12 @@
+import debug
+
+def test_func()
+ try
+ compile('def +() end')()
+ except .. as e, v
+ print('catch execption:', str(e) + ' >>>\n ' + str(v))
+ debug.traceback()
+ end
+end
+
+test_func()
diff --git a/lib/libesp32/berry/examples/fib_rec.be b/lib/libesp32/berry/examples/fib_rec.be
new file mode 100644
index 000000000..31ed3817b
--- /dev/null
+++ b/lib/libesp32/berry/examples/fib_rec.be
@@ -0,0 +1,12 @@
+import time
+
+def fib(x)
+ if x <= 2
+ return 1
+ end
+ return fib(x - 1) + fib(x - 2)
+end
+
+c = time.clock()
+print("fib:", fib(38)) # minimum stack size: 78!!
+print("time:", time.clock() - c, 's')
diff --git a/lib/libesp32/berry/examples/guess_number.be b/lib/libesp32/berry/examples/guess_number.be
new file mode 100644
index 000000000..6cbd07e7c
--- /dev/null
+++ b/lib/libesp32/berry/examples/guess_number.be
@@ -0,0 +1,26 @@
+import time
+import math
+
+math.srand(time.time())
+res = math.rand() % 100
+max_test = 7
+test = -1
+idx = 1
+print('Guess a number between 0 and 99. You have', max_test, 'chances.')
+while test != res && idx <= max_test
+ test = number(input(str(idx) + ': enter the number you guessed: '))
+ if type(test) != 'int'
+ print('This is not an integer. Continue!')
+ continue
+ elif test > res
+ print('This number is too large.')
+ elif test < res
+ print('This number is too small.')
+ end
+ idx = idx + 1
+end
+if test == res
+ print('You win!')
+else
+ print('You failed, the correct answer is', res)
+end
diff --git a/lib/libesp32/berry/examples/json.be b/lib/libesp32/berry/examples/json.be
new file mode 100644
index 000000000..d98dff8bb
--- /dev/null
+++ b/lib/libesp32/berry/examples/json.be
@@ -0,0 +1,4 @@
+import json
+print(json.load('{"key": "value"}'))
+print(json.dump({'test key': nil}))
+print(json.dump({'key1': nil, 45: true}, 'format'))
diff --git a/lib/libesp32/berry/examples/lambda.be b/lib/libesp32/berry/examples/lambda.be
new file mode 100644
index 000000000..1d0b709bb
--- /dev/null
+++ b/lib/libesp32/berry/examples/lambda.be
@@ -0,0 +1,8 @@
+# simple lambda example
+print((/a b c-> a * b + c)(2, 3, 4))
+
+# Y-Combinator and factorial functions
+Y = /f-> (/x-> f(/n-> x(x)(n)))(/x-> f(/n-> x(x)(n)))
+F = /f-> /x-> x ? f(x - 1) * x : 1
+fact = Y(F)
+print('fact(10) == ' .. fact(10))
diff --git a/lib/libesp32/berry/examples/listdir.be b/lib/libesp32/berry/examples/listdir.be
new file mode 100644
index 000000000..2dd880118
--- /dev/null
+++ b/lib/libesp32/berry/examples/listdir.be
@@ -0,0 +1,16 @@
+import os
+
+def scandir(path)
+ print('path: ' + path)
+ for name : os.listdir(path)
+ var fullname = os.path.join(path, name)
+ if os.path.isfile(fullname)
+ print('file: ' + fullname)
+ else
+ print('path: ' + fullname)
+ scandir(fullname)
+ end
+ end
+end
+
+scandir('.')
diff --git a/lib/libesp32/berry/examples/qsort.be b/lib/libesp32/berry/examples/qsort.be
new file mode 100644
index 000000000..b09b65672
--- /dev/null
+++ b/lib/libesp32/berry/examples/qsort.be
@@ -0,0 +1,42 @@
+def qsort(data)
+ # do once sort
+ def once(left, right)
+ var pivot = data[left] # use the 0th value as the pivot
+ while left < right # check if sort is complete
+ # put the value less than the pivot to the left
+ while left < right && data[right] >= pivot
+ right -= 1 # skip values greater than pivot
+ end
+ data[left] = data[right]
+ # put the value greater than the pivot on the right
+ while left < right && data[left] <= pivot
+ left += 1 # skip values less than pivot
+ end
+ data[right] = data[left]
+ end
+ # now we have the index of the pivot, store it
+ data[left] = pivot
+ return left # return the index of the pivot
+ end
+ # recursive quick sort algorithm
+ def _sort(left, right)
+ if left < right # executed when the array is not empty
+ var index = once(left, right) # get index of pivot for divide and conquer
+ _sort(left, index - 1) # sort the data on the left
+ _sort(index + 1, right) # sort the data on the right
+ end
+ end
+ # start quick sort
+ _sort(0, data.size() - 1)
+ return data
+end
+
+import time, math
+math.srand(time.time()) # sse system time as a random seed
+data = []
+# put 20 random numbers into the array
+for i : 1 .. 20
+ data.push(math.rand() % 100)
+end
+# sort and print
+print(qsort(data))
diff --git a/lib/libesp32/berry/examples/repl.be b/lib/libesp32/berry/examples/repl.be
new file mode 100644
index 000000000..aac26b0a1
--- /dev/null
+++ b/lib/libesp32/berry/examples/repl.be
@@ -0,0 +1,61 @@
+do
+ def ismult(msg)
+ import string
+ return string.split(msg, -5)[1] == '\'EOS\''
+ end
+
+ def multline(src, msg)
+ if !ismult(msg)
+ print('syntax_error: ' + msg)
+ return
+ end
+ while true
+ try
+ src += '\n' + input('>> ')
+ return compile(src)
+ except 'syntax_error' as e, m
+ if !ismult(m)
+ print('syntax_error: ' + m)
+ return
+ end
+ end
+ end
+ end
+
+ def parse()
+ var fun, src = input('> ')
+ try
+ fun = compile('return (' + src + ')')
+ except 'syntax_error' as e, m
+ try
+ fun = compile(src)
+ except 'syntax_error' as e, m
+ fun = multline(src, m)
+ end
+ end
+ return fun
+ end
+
+ def run(fun)
+ try
+ var res = fun()
+ if res print(res) end
+ except .. as e, m
+ import debug
+ print(e .. ': ' .. m)
+ debug.traceback()
+ end
+ end
+
+ def repl()
+ while true
+ var fun = parse()
+ if fun != nil
+ run(fun)
+ end
+ end
+ end
+
+ print("Berry Berry REPL!")
+ repl()
+end
diff --git a/lib/libesp32/berry/examples/string.be b/lib/libesp32/berry/examples/string.be
new file mode 100644
index 000000000..299834e21
--- /dev/null
+++ b/lib/libesp32/berry/examples/string.be
@@ -0,0 +1,32 @@
+s = "This is a long string test. 0123456789 abcdefg ABCDEFG"
+print(s)
+
+a = .5
+print(a)
+
+import string as s
+
+print(s.hex(0x45678ABCD, 16))
+
+def bin(x, num)
+ assert(type(x) == 'int', 'the type of \'x\' must be integer')
+ # test the 'x' bits
+ var bits = 1
+ for i : 0 .. 62
+ if x & (1 << 63 - i)
+ bits = 64 - i
+ break
+ end
+ end
+ if type(num) == 'int' && num > 0 && num <= 64
+ bits = bits < num ? num : bits
+ end
+ var result = ''
+ bits -= 1
+ for i : 0 .. bits
+ result += x & (1 << (bits - i)) ? '1' : '0'
+ end
+ return result
+end
+
+print(bin(33))
diff --git a/lib/libesp32/berry/examples/strmod.be b/lib/libesp32/berry/examples/strmod.be
new file mode 100644
index 000000000..8660f5b4e
--- /dev/null
+++ b/lib/libesp32/berry/examples/strmod.be
@@ -0,0 +1,7 @@
+import string
+
+print(string.format('%.3d', 12))
+print(string.format('%.3f', 12))
+print(string.format('%20.7f', 14.5))
+print(string.format('-- %-40s ---', 'this is a string format test'))
+print(string.format('-- %40s ---', 'this is a string format test'))
diff --git a/lib/libesp32/berry/gen.sh b/lib/libesp32/berry/gen.sh
new file mode 100755
index 000000000..303a62c95
--- /dev/null
+++ b/lib/libesp32/berry/gen.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+python3 tools/pycoc/main.py -o generate src default ../berry_mapping/src -c default/berry_conf.h
diff --git a/lib/libesp32/berry/generate/be_const_strtab.h b/lib/libesp32/berry/generate/be_const_strtab.h
new file mode 100644
index 000000000..50198eb8f
--- /dev/null
+++ b/lib/libesp32/berry/generate/be_const_strtab.h
@@ -0,0 +1,741 @@
+extern const bcstring be_const_str_;
+extern const bcstring be_const_str_AES_GCM;
+extern const bcstring be_const_str_AXP192;
+extern const bcstring be_const_str_Animate_X20pc_X20is_X20out_X20of_X20range;
+extern const bcstring be_const_str_AudioFileSource;
+extern const bcstring be_const_str_AudioFileSourceFS;
+extern const bcstring be_const_str_AudioGenerator;
+extern const bcstring be_const_str_AudioGeneratorMP3;
+extern const bcstring be_const_str_AudioGeneratorWAV;
+extern const bcstring be_const_str_AudioOutput;
+extern const bcstring be_const_str_AudioOutputI2S;
+extern const bcstring be_const_str_Auto_X2Dconfiguration;
+extern const bcstring be_const_str_BRY_X3A_X20ERROR_X2C_X20bad_X20json_X3A_X20;
+extern const bcstring be_const_str_BRY_X3A_X20Exception_X3E_X20_X27_X25s_X27_X20_X2D_X20_X25s;
+extern const bcstring be_const_str_BRY_X3A_X20could_X20not_X20save_X20compiled_X20file_X20_X25s_X20_X28_X25s_X29;
+extern const bcstring be_const_str_BRY_X3A_X20failed_X20to_X20load_X20_persist_X2Ejson;
+extern const bcstring be_const_str_BUTTON_CONFIGURATION;
+extern const bcstring be_const_str_CFG_X3A_X20Exception_X3E_X20_X27_X25s_X27_X20_X2D_X20_X25s;
+extern const bcstring be_const_str_CFG_X3A_X20_X27init_X2Ebat_X27_X20done_X2C_X20restarting;
+extern const bcstring be_const_str_CFG_X3A_X20could_X20not_X20run_X20_X25s_X20_X28_X25s_X20_X2D_X20_X25s_X29;
+extern const bcstring be_const_str_CFG_X3A_X20downloading_X20_X27_X25s_X27;
+extern const bcstring be_const_str_CFG_X3A_X20exception_X20_X27_X25s_X27_X20_X2D_X20_X27_X25s_X27;
+extern const bcstring be_const_str_CFG_X3A_X20loaded_X20_X20;
+extern const bcstring be_const_str_CFG_X3A_X20loaded_X20_X27_X25s_X27;
+extern const bcstring be_const_str_CFG_X3A_X20loading_X20;
+extern const bcstring be_const_str_CFG_X3A_X20loading_X20_X27_X25s_X27;
+extern const bcstring be_const_str_CFG_X3A_X20multiple_X20autoconf_X20files_X20found_X2C_X20aborting_X20_X28_X27_X25s_X27_X20_X2B_X20_X27_X25s_X27_X29;
+extern const bcstring be_const_str_CFG_X3A_X20no_X20_X27_X2A_X2Eautoconf_X27_X20file_X20found;
+extern const bcstring be_const_str_CFG_X3A_X20ran_X20_X20;
+extern const bcstring be_const_str_CFG_X3A_X20removed_X20file_X20_X27_X25s_X27;
+extern const bcstring be_const_str_CFG_X3A_X20removing_X20autoconf_X20files;
+extern const bcstring be_const_str_CFG_X3A_X20removing_X20first_X20time_X20marker;
+extern const bcstring be_const_str_CFG_X3A_X20return_code_X3D_X25i;
+extern const bcstring be_const_str_CFG_X3A_X20running_X20;
+extern const bcstring be_const_str_CFG_X3A_X20skipping_X20_X27display_X2Eini_X27_X20because_X20already_X20present_X20in_X20file_X2Dsystem;
+extern const bcstring be_const_str_COLOR_BLACK;
+extern const bcstring be_const_str_COLOR_WHITE;
+extern const bcstring be_const_str_EC_C25519;
+extern const bcstring be_const_str_EVENT_DRAW_MAIN;
+extern const bcstring be_const_str_EVENT_DRAW_PART_BEGIN;
+extern const bcstring be_const_str_EVENT_DRAW_PART_END;
+extern const bcstring be_const_str_False;
+extern const bcstring be_const_str_GET;
+extern const bcstring be_const_str_HTTP_GET;
+extern const bcstring be_const_str_HTTP_POST;
+extern const bcstring be_const_str_I2C_Driver;
+extern const bcstring be_const_str_I2C_X3A;
+extern const bcstring be_const_str_LVG_X3A_X20call_X20to_X20unsupported_X20callback;
+extern const bcstring be_const_str_Leds;
+extern const bcstring be_const_str_MD5;
+extern const bcstring be_const_str_None;
+extern const bcstring be_const_str_OPTION_A;
+extern const bcstring be_const_str_OneWire;
+extern const bcstring be_const_str_PART_MAIN;
+extern const bcstring be_const_str_POST;
+extern const bcstring be_const_str_Parameter_X20error;
+extern const bcstring be_const_str_RES_OK;
+extern const bcstring be_const_str_Restart_X201;
+extern const bcstring be_const_str_SERIAL_5E1;
+extern const bcstring be_const_str_SERIAL_5E2;
+extern const bcstring be_const_str_SERIAL_5N1;
+extern const bcstring be_const_str_SERIAL_5N2;
+extern const bcstring be_const_str_SERIAL_5O1;
+extern const bcstring be_const_str_SERIAL_5O2;
+extern const bcstring be_const_str_SERIAL_6E1;
+extern const bcstring be_const_str_SERIAL_6E2;
+extern const bcstring be_const_str_SERIAL_6N1;
+extern const bcstring be_const_str_SERIAL_6N2;
+extern const bcstring be_const_str_SERIAL_6O1;
+extern const bcstring be_const_str_SERIAL_6O2;
+extern const bcstring be_const_str_SERIAL_7E1;
+extern const bcstring be_const_str_SERIAL_7E2;
+extern const bcstring be_const_str_SERIAL_7N1;
+extern const bcstring be_const_str_SERIAL_7N2;
+extern const bcstring be_const_str_SERIAL_7O1;
+extern const bcstring be_const_str_SERIAL_7O2;
+extern const bcstring be_const_str_SERIAL_8E1;
+extern const bcstring be_const_str_SERIAL_8E2;
+extern const bcstring be_const_str_SERIAL_8N1;
+extern const bcstring be_const_str_SERIAL_8N2;
+extern const bcstring be_const_str_SERIAL_8O1;
+extern const bcstring be_const_str_SERIAL_8O2;
+extern const bcstring be_const_str_SK6812_GRBW;
+extern const bcstring be_const_str_STATE_DEFAULT;
+extern const bcstring be_const_str_TAP_X3A_X20found_X20Tasmota_X20App_X20_X27_X25s_X27;
+extern const bcstring be_const_str_Tasmota;
+extern const bcstring be_const_str_Tele;
+extern const bcstring be_const_str_Timer;
+extern const bcstring be_const_str_True;
+extern const bcstring be_const_str_Unknown_X20command;
+extern const bcstring be_const_str_WS2812;
+extern const bcstring be_const_str_WS2812_GRB;
+extern const bcstring be_const_str_Wire;
+extern const bcstring be_const_str__;
+extern const bcstring be_const_str__X0A;
+extern const bcstring be_const_str__X20;
+extern const bcstring be_const_str__X21_X3D;
+extern const bcstring be_const_str__X21_X3D_X3D;
+extern const bcstring be_const_str__X23;
+extern const bcstring be_const_str__X23autoexec_X2Ebat;
+extern const bcstring be_const_str__X23autoexec_X2Ebe;
+extern const bcstring be_const_str__X23display_X2Eini;
+extern const bcstring be_const_str__X23init_X2Ebat;
+extern const bcstring be_const_str__X23preinit_X2Ebe;
+extern const bcstring be_const_str__X2502d_X25s_X2502d;
+extern const bcstring be_const_str__X2504d_X2D_X2502d_X2D_X2502dT_X2502d_X3A_X2502d_X3A_X2502d;
+extern const bcstring be_const_str__X25s_X2Eautoconf;
+extern const bcstring be_const_str__X26lt_X3BError_X3A_X20apply_X20new_X20or_X20remove_X26gt_X3B;
+extern const bcstring be_const_str__X26lt_X3BNone_X26gt_X3B;
+extern const bcstring be_const_str__X28_X29;
+extern const bcstring be_const_str__X2B;
+extern const bcstring be_const_str__X2C;
+extern const bcstring be_const_str__X2D_X2D_X3A_X2D_X2D;
+extern const bcstring be_const_str__X2E;
+extern const bcstring be_const_str__X2E_X2E;
+extern const bcstring be_const_str__X2Eautoconf;
+extern const bcstring be_const_str__X2Ebe;
+extern const bcstring be_const_str__X2Ebec;
+extern const bcstring be_const_str__X2Elen;
+extern const bcstring be_const_str__X2Ep;
+extern const bcstring be_const_str__X2Ep1;
+extern const bcstring be_const_str__X2Ep2;
+extern const bcstring be_const_str__X2Esize;
+extern const bcstring be_const_str__X2Etapp;
+extern const bcstring be_const_str__X2Ew;
+extern const bcstring be_const_str__X2F;
+extern const bcstring be_const_str__X2F_X2Eautoconf;
+extern const bcstring be_const_str__X2F_X3Frst_X3D;
+extern const bcstring be_const_str__X2Fac;
+extern const bcstring be_const_str__X3A;
+extern const bcstring be_const_str__X3C;
+extern const bcstring be_const_str__X3C_X2Fform_X3E_X3C_X2Fp_X3E;
+extern const bcstring be_const_str__X3C_X2Fselect_X3E_X3Cp_X3E_X3C_X2Fp_X3E;
+extern const bcstring be_const_str__X3C_X3D;
+extern const bcstring be_const_str__X3Cbutton_X20name_X3D_X27reapply_X27_X20class_X3D_X27button_X20bgrn_X27_X3ERe_X2Dapply_X20current_X20configuration_X3C_X2Fbutton_X3E;
+extern const bcstring be_const_str__X3Cbutton_X20name_X3D_X27zipapply_X27_X20class_X3D_X27button_X20bgrn_X27_X3EApply_X20configuration_X3C_X2Fbutton_X3E;
+extern const bcstring be_const_str__X3Cfieldset_X3E_X3Cstyle_X3E_X2Ebdis_X7Bbackground_X3A_X23888_X3B_X7D_X2Ebdis_X3Ahover_X7Bbackground_X3A_X23888_X3B_X7D_X3C_X2Fstyle_X3E;
+extern const bcstring be_const_str__X3Cinstance_X3A_X20_X25s_X28_X25s_X2C_X20_X25s_X2C_X20_X25s_X29;
+extern const bcstring be_const_str__X3Clabel_X3EChoose_X20a_X20device_X20configuration_X3A_X3C_X2Flabel_X3E_X3Cbr_X3E;
+extern const bcstring be_const_str__X3Clambda_X3E;
+extern const bcstring be_const_str__X3Clegend_X3E_X3Cb_X20title_X3D_X27Autoconfiguration_X27_X3E_X26nbsp_X3BCurrent_X20auto_X2Dconfiguration_X3C_X2Fb_X3E_X3C_X2Flegend_X3E;
+extern const bcstring be_const_str__X3Clegend_X3E_X3Cb_X20title_X3D_X27New_X20autoconf_X27_X3E_X26nbsp_X3BSelect_X20new_X20auto_X2Dconfiguration_X3C_X2Fb_X3E_X3C_X2Flegend_X3E;
+extern const bcstring be_const_str__X3Coption_X20value_X3D_X27_X25s_X27_X3E_X25s_X3C_X2Foption_X3E;
+extern const bcstring be_const_str__X3Coption_X20value_X3D_X27reset_X27_X3E_X26lt_X3BRemove_X20autoconf_X26gt_X3B_X3C_X2Foption_X3E;
+extern const bcstring be_const_str__X3Cp_X20style_X3D_X27width_X3A340px_X3B_X27_X3E_X3Cb_X3EException_X3A_X3C_X2Fb_X3E_X3Cbr_X3E_X27_X25s_X27_X3Cbr_X3E_X25s_X3C_X2Fp_X3E;
+extern const bcstring be_const_str__X3Cp_X3ECurrent_X20configuration_X3A_X20_X3C_X2Fp_X3E_X3Cp_X3E_X3Cb_X3E_X25s_X3C_X2Fb_X3E_X3C_X2Fp_X3E;
+extern const bcstring be_const_str__X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E;
+extern const bcstring be_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;
+extern const bcstring be_const_str__X3Cp_X3E_X3Cform_X20id_X3Dreapply_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20action_X3D_X27_X2Fac_X27_X20method_X3D_X27post_X27_X20;
+extern const bcstring be_const_str__X3Cp_X3E_X3Cform_X20id_X3Dzip_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20action_X3D_X27_X2Fac_X27_X20method_X3D_X27post_X27_X20;
+extern const bcstring be_const_str__X3Cp_X3E_X3Csmall_X3E_X26nbsp_X3B_X28This_X20feature_X20requires_X20an_X20internet_X20connection_X29_X3C_X2Fsmall_X3E_X3C_X2Fp_X3E;
+extern const bcstring be_const_str__X3Cselect_X20name_X3D_X27zip_X27_X3E;
+extern const bcstring be_const_str__X3D;
+extern const bcstring be_const_str__X3D_X3C_X3E_X21;
+extern const bcstring be_const_str__X3D_X3D;
+extern const bcstring be_const_str__X3E;
+extern const bcstring be_const_str__X3E_X3D;
+extern const bcstring be_const_str__X3F;
+extern const bcstring be_const_str__X5B;
+extern const bcstring be_const_str__X5D;
+extern const bcstring be_const_str__X7B;
+extern const bcstring be_const_str__X7B_X7D;
+extern const bcstring be_const_str__X7Bs_X7DBatt_X20Current_X7Bm_X7D_X25_X2E1f_X20mA_X7Be_X7D;
+extern const bcstring be_const_str__X7Bs_X7DBatt_X20Voltage_X7Bm_X7D_X25_X2E3f_X20V_X7Be_X7D;
+extern const bcstring be_const_str__X7Bs_X7DTemp_X20AXP_X7Bm_X7D_X25_X2E1f_X20_XB0C_X7Be_X7D;
+extern const bcstring be_const_str__X7Bs_X7DVBus_X20Current_X7Bm_X7D_X25_X2E1f_X20mA_X7Be_X7D;
+extern const bcstring be_const_str__X7Bs_X7DVBus_X20Voltage_X7Bm_X7D_X25_X2E3f_X20V_X7Be_X7D;
+extern const bcstring be_const_str__X7D;
+extern const bcstring be_const_str___iterator__;
+extern const bcstring be_const_str___lower__;
+extern const bcstring be_const_str___upper__;
+extern const bcstring be_const_str__anonymous_;
+extern const bcstring be_const_str__archive;
+extern const bcstring be_const_str__available;
+extern const bcstring be_const_str__begin_transmission;
+extern const bcstring be_const_str__buffer;
+extern const bcstring be_const_str__ccmd;
+extern const bcstring be_const_str__class;
+extern const bcstring be_const_str__cmd;
+extern const bcstring be_const_str__debug_present;
+extern const bcstring be_const_str__def;
+extern const bcstring be_const_str__dirty;
+extern const bcstring be_const_str__drivers;
+extern const bcstring be_const_str__end_transmission;
+extern const bcstring be_const_str__energy;
+extern const bcstring be_const_str__error;
+extern const bcstring be_const_str__filename;
+extern const bcstring be_const_str__global_addr;
+extern const bcstring be_const_str__global_def;
+extern const bcstring be_const_str__lvgl;
+extern const bcstring be_const_str__p;
+extern const bcstring be_const_str__persist_X2Ejson;
+extern const bcstring be_const_str__ptr;
+extern const bcstring be_const_str__read;
+extern const bcstring be_const_str__request_from;
+extern const bcstring be_const_str__rules;
+extern const bcstring be_const_str__settings_def;
+extern const bcstring be_const_str__settings_ptr;
+extern const bcstring be_const_str__t;
+extern const bcstring be_const_str__timers;
+extern const bcstring be_const_str__write;
+extern const bcstring be_const_str_a;
+extern const bcstring be_const_str_abs;
+extern const bcstring be_const_str_acos;
+extern const bcstring be_const_str_add;
+extern const bcstring be_const_str_add_anim;
+extern const bcstring be_const_str_add_cmd;
+extern const bcstring be_const_str_add_driver;
+extern const bcstring be_const_str_add_header;
+extern const bcstring be_const_str_add_rule;
+extern const bcstring be_const_str_addr;
+extern const bcstring be_const_str_allocated;
+extern const bcstring be_const_str_alternate;
+extern const bcstring be_const_str_animate;
+extern const bcstring be_const_str_animators;
+extern const bcstring be_const_str_arch;
+extern const bcstring be_const_str_area;
+extern const bcstring be_const_str_arg;
+extern const bcstring be_const_str_arg_X20must_X20be_X20a_X20subclass_X20of_X20lv_obj;
+extern const bcstring be_const_str_arg_name;
+extern const bcstring be_const_str_arg_size;
+extern const bcstring be_const_str_as;
+extern const bcstring be_const_str_asin;
+extern const bcstring be_const_str_assert;
+extern const bcstring be_const_str_asstring;
+extern const bcstring be_const_str_atan;
+extern const bcstring be_const_str_atan2;
+extern const bcstring be_const_str_atleast1;
+extern const bcstring be_const_str_attrdump;
+extern const bcstring be_const_str_autoexec;
+extern const bcstring be_const_str_autorun;
+extern const bcstring be_const_str_available;
+extern const bcstring be_const_str_b;
+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_bool;
+extern const bcstring be_const_str_break;
+extern const bcstring be_const_str_bri;
+extern const bcstring be_const_str_bus;
+extern const bcstring be_const_str_button_pressed;
+extern const bcstring be_const_str_byte;
+extern const bcstring be_const_str_bytes;
+extern const bcstring be_const_str_c;
+extern const bcstring be_const_str_call;
+extern const bcstring be_const_str_call_native;
+extern const bcstring be_const_str_calldepth;
+extern const bcstring be_const_str_can_show;
+extern const bcstring be_const_str_cb;
+extern const bcstring be_const_str_cb_do_nothing;
+extern const bcstring be_const_str_cb_event_closure;
+extern const bcstring be_const_str_cb_obj;
+extern const bcstring be_const_str_ceil;
+extern const bcstring be_const_str_char;
+extern const bcstring be_const_str_chars_in_string;
+extern const bcstring be_const_str_check_privileged_access;
+extern const bcstring be_const_str_class;
+extern const bcstring be_const_str_class_init_obj;
+extern const bcstring be_const_str_classname;
+extern const bcstring be_const_str_classof;
+extern const bcstring be_const_str_clear;
+extern const bcstring be_const_str_clear_first_time;
+extern const bcstring be_const_str_clear_to;
+extern const bcstring be_const_str_close;
+extern const bcstring be_const_str_closure;
+extern const bcstring be_const_str_cmd;
+extern const bcstring be_const_str_cmd_res;
+extern const bcstring be_const_str_code;
+extern const bcstring be_const_str_codedump;
+extern const bcstring be_const_str_collect;
+extern const bcstring be_const_str_color;
+extern const bcstring be_const_str_compile;
+extern const bcstring be_const_str_compress;
+extern const bcstring be_const_str_concat;
+extern const bcstring be_const_str_connect;
+extern const bcstring be_const_str_connected;
+extern const bcstring be_const_str_connection_error;
+extern const bcstring be_const_str_constructor_cb;
+extern const bcstring be_const_str_contains;
+extern const bcstring be_const_str_content_button;
+extern const bcstring be_const_str_content_flush;
+extern const bcstring be_const_str_content_send;
+extern const bcstring be_const_str_content_send_style;
+extern const bcstring be_const_str_content_start;
+extern const bcstring be_const_str_content_stop;
+extern const bcstring be_const_str_continue;
+extern const bcstring be_const_str_copy;
+extern const bcstring be_const_str_cos;
+extern const bcstring be_const_str_cosh;
+extern const bcstring be_const_str_couldn_X27t_X20not_X20initialize_X20noepixelbus;
+extern const bcstring be_const_str_count;
+extern const bcstring be_const_str_counters;
+extern const bcstring be_const_str_create_custom_widget;
+extern const bcstring be_const_str_create_matrix;
+extern const bcstring be_const_str_create_segment;
+extern const bcstring be_const_str_ctor;
+extern const bcstring be_const_str_ctypes_bytes;
+extern const bcstring be_const_str_ctypes_bytes_dyn;
+extern const bcstring be_const_str_dac_voltage;
+extern const bcstring be_const_str_day;
+extern const bcstring be_const_str_debug;
+extern const bcstring be_const_str_decompress;
+extern const bcstring be_const_str_decrypt;
+extern const bcstring be_const_str_def;
+extern const bcstring be_const_str_deg;
+extern const bcstring be_const_str_deinit;
+extern const bcstring be_const_str_del;
+extern const bcstring be_const_str_delay;
+extern const bcstring be_const_str_delete_all_configs;
+extern const bcstring be_const_str_depower;
+extern const bcstring be_const_str_deregister_obj;
+extern const bcstring be_const_str_destructor_cb;
+extern const bcstring be_const_str_detect;
+extern const bcstring be_const_str_detected_X20on_X20bus;
+extern const bcstring be_const_str_digital_read;
+extern const bcstring be_const_str_digital_write;
+extern const bcstring be_const_str_dirty;
+extern const bcstring be_const_str_display;
+extern const bcstring be_const_str_display_X2Eini;
+extern const bcstring be_const_str_do;
+extern const bcstring be_const_str_draw_arc;
+extern const bcstring be_const_str_draw_line;
+extern const bcstring be_const_str_draw_line_dsc;
+extern const bcstring be_const_str_draw_line_dsc_init;
+extern const bcstring be_const_str_due;
+extern const bcstring be_const_str_dump;
+extern const bcstring be_const_str_duration;
+extern const bcstring be_const_str_editable;
+extern const bcstring be_const_str_elif;
+extern const bcstring be_const_str_else;
+extern const bcstring be_const_str_enabled;
+extern const bcstring be_const_str_encrypt;
+extern const bcstring be_const_str_end;
+extern const bcstring be_const_str_energy_struct;
+extern const bcstring be_const_str_engine;
+extern const bcstring be_const_str_erase;
+extern const bcstring be_const_str_escape;
+extern const bcstring be_const_str_eth;
+extern const bcstring be_const_str_event;
+extern const bcstring be_const_str_event_cb;
+extern const bcstring be_const_str_event_send;
+extern const bcstring be_const_str_every_100ms;
+extern const bcstring be_const_str_every_50ms;
+extern const bcstring be_const_str_every_second;
+extern const bcstring be_const_str_except;
+extern const bcstring be_const_str_exec_cmd;
+extern const bcstring be_const_str_exec_rules;
+extern const bcstring be_const_str_exec_tele;
+extern const bcstring be_const_str_exists;
+extern const bcstring be_const_str_exp;
+extern const bcstring be_const_str_f;
+extern const bcstring be_const_str_false;
+extern const bcstring be_const_str_file;
+extern const bcstring be_const_str_file_X20extension_X20is_X20not_X20_X27_X2Ebe_X27_X20or_X20_X27_X2Ebec_X27;
+extern const bcstring be_const_str_files;
+extern const bcstring be_const_str_find;
+extern const bcstring be_const_str_find_key_i;
+extern const bcstring be_const_str_find_op;
+extern const bcstring be_const_str_finish;
+extern const bcstring be_const_str_floor;
+extern const bcstring be_const_str_flush;
+extern const bcstring be_const_str_for;
+extern const bcstring be_const_str_format;
+extern const bcstring be_const_str_from_to;
+extern const bcstring be_const_str_fromb64;
+extern const bcstring be_const_str_fromptr;
+extern const bcstring be_const_str_fromstring;
+extern const bcstring be_const_str_function;
+extern const bcstring be_const_str_gamma;
+extern const bcstring be_const_str_gamma10;
+extern const bcstring be_const_str_gamma8;
+extern const bcstring be_const_str_gc;
+extern const bcstring be_const_str_gen_cb;
+extern const bcstring be_const_str_get;
+extern const bcstring be_const_str_get_alternate;
+extern const bcstring be_const_str_get_aps_voltage;
+extern const bcstring be_const_str_get_bat_charge_current;
+extern const bcstring be_const_str_get_bat_current;
+extern const bcstring be_const_str_get_bat_power;
+extern const bcstring be_const_str_get_bat_voltage;
+extern const bcstring be_const_str_get_battery_chargin_status;
+extern const bcstring be_const_str_get_bri;
+extern const bcstring be_const_str_get_cb_list;
+extern const bcstring be_const_str_get_coords;
+extern const bcstring be_const_str_get_current_module_name;
+extern const bcstring be_const_str_get_current_module_path;
+extern const bcstring be_const_str_get_free_heap;
+extern const bcstring be_const_str_get_height;
+extern const bcstring be_const_str_get_input_power_status;
+extern const bcstring be_const_str_get_light;
+extern const bcstring be_const_str_get_object_from_ptr;
+extern const bcstring be_const_str_get_option;
+extern const bcstring be_const_str_get_percentage;
+extern const bcstring be_const_str_get_pixel_color;
+extern const bcstring be_const_str_get_power;
+extern const bcstring be_const_str_get_size;
+extern const bcstring be_const_str_get_string;
+extern const bcstring be_const_str_get_style_bg_color;
+extern const bcstring be_const_str_get_style_line_color;
+extern const bcstring be_const_str_get_style_pad_right;
+extern const bcstring be_const_str_get_switch;
+extern const bcstring be_const_str_get_tasmota;
+extern const bcstring be_const_str_get_temp;
+extern const bcstring be_const_str_get_vbus_current;
+extern const bcstring be_const_str_get_vbus_voltage;
+extern const bcstring be_const_str_get_warning_level;
+extern const bcstring be_const_str_get_width;
+extern const bcstring be_const_str_getbits;
+extern const bcstring be_const_str_geti;
+extern const bcstring be_const_str_global;
+extern const bcstring be_const_str_gpio;
+extern const bcstring be_const_str_group_def;
+extern const bcstring be_const_str_h;
+extern const bcstring be_const_str_has;
+extern const bcstring be_const_str_has_arg;
+extern const bcstring be_const_str_height_def;
+extern const bcstring be_const_str_hex;
+extern const bcstring be_const_str_hour;
+extern const bcstring be_const_str_hs2rgb;
+extern const bcstring be_const_str_https_X3A_X2F_X2Fraw_X2Egithubusercontent_X2Ecom_X2Ftasmota_X2Fautoconf_X2Fmain_X2F_X25s_X2F_X25s_X2Eautoconf;
+extern const bcstring be_const_str_https_X3A_X2F_X2Fraw_X2Egithubusercontent_X2Ecom_X2Ftasmota_X2Fautoconf_X2Fmain_X2F_X25s_manifest_X2Ejson;
+extern const bcstring be_const_str_i2c_enabled;
+extern const bcstring be_const_str_id;
+extern const bcstring be_const_str_if;
+extern const bcstring be_const_str_imax;
+extern const bcstring be_const_str_imin;
+extern const bcstring be_const_str_import;
+extern const bcstring be_const_str_init;
+extern const bcstring be_const_str_init_draw_line_dsc;
+extern const bcstring be_const_str_input;
+extern const bcstring be_const_str_ins_goto;
+extern const bcstring be_const_str_ins_ramp;
+extern const bcstring be_const_str_ins_time;
+extern const bcstring be_const_str_insert;
+extern const bcstring be_const_str_instance;
+extern const bcstring be_const_str_instance_size;
+extern const bcstring be_const_str_int;
+extern const bcstring be_const_str_internal_error;
+extern const bcstring be_const_str_introspect;
+extern const bcstring be_const_str_invalidate;
+extern const bcstring be_const_str_io_error;
+extern const bcstring be_const_str_ip;
+extern const bcstring be_const_str_is_dirty;
+extern const bcstring be_const_str_is_first_time;
+extern const bcstring be_const_str_is_running;
+extern const bcstring be_const_str_isinstance;
+extern const bcstring be_const_str_isnan;
+extern const bcstring be_const_str_isrunning;
+extern const bcstring be_const_str_issubclass;
+extern const bcstring be_const_str_item;
+extern const bcstring be_const_str_iter;
+extern const bcstring be_const_str_json;
+extern const bcstring be_const_str_json_append;
+extern const bcstring be_const_str_json_fdump;
+extern const bcstring be_const_str_json_fdump_any;
+extern const bcstring be_const_str_json_fdump_list;
+extern const bcstring be_const_str_json_fdump_map;
+extern const bcstring be_const_str_k;
+extern const bcstring be_const_str_keys;
+extern const bcstring be_const_str_kv;
+extern const bcstring be_const_str_last_modified;
+extern const bcstring be_const_str_leds;
+extern const bcstring be_const_str_length_X20in_X20bits_X20must_X20be_X20between_X200_X20and_X2032;
+extern const bcstring be_const_str_light;
+extern const bcstring be_const_str_line_dsc;
+extern const bcstring be_const_str_list;
+extern const bcstring be_const_str_listdir;
+extern const bcstring be_const_str_load;
+extern const bcstring be_const_str_load_templates;
+extern const bcstring be_const_str_local;
+extern const bcstring be_const_str_log;
+extern const bcstring be_const_str_log10;
+extern const bcstring be_const_str_loop;
+extern const bcstring be_const_str_lower;
+extern const bcstring be_const_str_lv;
+extern const bcstring be_const_str_lv_event;
+extern const bcstring be_const_str_lv_event_cb;
+extern const bcstring be_const_str_lv_obj;
+extern const bcstring be_const_str_lv_obj_class;
+extern const bcstring be_const_str_lvgl_event_dispatch;
+extern const bcstring be_const_str_map;
+extern const bcstring be_const_str_math;
+extern const bcstring be_const_str_matrix;
+extern const bcstring be_const_str_member;
+extern const bcstring be_const_str_members;
+extern const bcstring be_const_str_memory;
+extern const bcstring be_const_str_millis;
+extern const bcstring be_const_str_min;
+extern const bcstring be_const_str_minute;
+extern const bcstring be_const_str_module;
+extern const bcstring be_const_str_month;
+extern const bcstring be_const_str_name;
+extern const bcstring be_const_str_nan;
+extern const bcstring be_const_str_nil;
+extern const bcstring be_const_str_no_X20GPIO_X20specified_X20for_X20neopixelbus;
+extern const bcstring be_const_str_null_cb;
+extern const bcstring be_const_str_number;
+extern const bcstring be_const_str_obj_class_create_obj;
+extern const bcstring be_const_str_obj_event_base;
+extern const bcstring be_const_str_offset;
+extern const bcstring be_const_str_offseta;
+extern const bcstring be_const_str_on;
+extern const bcstring be_const_str_onsubmit_X3D_X27return_X20confirm_X28_X22This_X20will_X20cause_X20a_X20restart_X2E_X22_X29_X3B_X27_X3E;
+extern const bcstring be_const_str_onsubmit_X3D_X27return_X20confirm_X28_X22This_X20will_X20change_X20the_X20current_X20configuration_X20and_X20cause_X20a_X20restart_X2E_X22_X29_X3B_X27_X3E;
+extern const bcstring be_const_str_open;
+extern const bcstring be_const_str_out_X20of_X20range;
+extern const bcstring be_const_str_p1;
+extern const bcstring be_const_str_p2;
+extern const bcstring be_const_str_page_autoconf_ctl;
+extern const bcstring be_const_str_page_autoconf_mgr;
+extern const bcstring be_const_str_param;
+extern const bcstring be_const_str_path;
+extern const bcstring be_const_str_pc;
+extern const bcstring be_const_str_pc_abs;
+extern const bcstring be_const_str_pc_rel;
+extern const bcstring be_const_str_percentage;
+extern const bcstring be_const_str_persist;
+extern const bcstring be_const_str_persist_X2E_p_X20is_X20not_X20a_X20map;
+extern const bcstring be_const_str_pi;
+extern const bcstring be_const_str_pin;
+extern const bcstring be_const_str_pin_mode;
+extern const bcstring be_const_str_pin_used;
+extern const bcstring be_const_str_pixel_count;
+extern const bcstring be_const_str_pixel_size;
+extern const bcstring be_const_str_pixels_buffer;
+extern const bcstring be_const_str_point;
+extern const bcstring be_const_str_pop;
+extern const bcstring be_const_str_pop_path;
+extern const bcstring be_const_str_pow;
+extern const bcstring be_const_str_preinit;
+extern const bcstring be_const_str_print;
+extern const bcstring be_const_str_public_key;
+extern const bcstring be_const_str_publish;
+extern const bcstring be_const_str_publish_result;
+extern const bcstring be_const_str_push;
+extern const bcstring be_const_str_push_path;
+extern const bcstring be_const_str_quality;
+extern const bcstring be_const_str_r;
+extern const bcstring be_const_str_rad;
+extern const bcstring be_const_str_raise;
+extern const bcstring be_const_str_rand;
+extern const bcstring be_const_str_range;
+extern const bcstring be_const_str_read;
+extern const bcstring be_const_str_read12;
+extern const bcstring be_const_str_read13;
+extern const bcstring be_const_str_read24;
+extern const bcstring be_const_str_read32;
+extern const bcstring be_const_str_read8;
+extern const bcstring be_const_str_read_bytes;
+extern const bcstring be_const_str_read_sensors;
+extern const bcstring be_const_str_readbytes;
+extern const bcstring be_const_str_readline;
+extern const bcstring be_const_str_real;
+extern const bcstring be_const_str_reapply;
+extern const bcstring be_const_str_redirect;
+extern const bcstring be_const_str_reduce;
+extern const bcstring be_const_str_refr_size;
+extern const bcstring be_const_str_register_obj;
+extern const bcstring be_const_str_remove;
+extern const bcstring be_const_str_remove_cmd;
+extern const bcstring be_const_str_remove_driver;
+extern const bcstring be_const_str_remove_rule;
+extern const bcstring be_const_str_remove_timer;
+extern const bcstring be_const_str_reset;
+extern const bcstring be_const_str_reset_search;
+extern const bcstring be_const_str_resize;
+extern const bcstring be_const_str_resolvecmnd;
+extern const bcstring be_const_str_resp_cmnd;
+extern const bcstring be_const_str_resp_cmnd_done;
+extern const bcstring be_const_str_resp_cmnd_error;
+extern const bcstring be_const_str_resp_cmnd_failed;
+extern const bcstring be_const_str_resp_cmnd_str;
+extern const bcstring be_const_str_response_append;
+extern const bcstring be_const_str_return;
+extern const bcstring be_const_str_return_X20code_X3D_X25i;
+extern const bcstring be_const_str_reverse;
+extern const bcstring be_const_str_reverse_gamma10;
+extern const bcstring be_const_str_rotate;
+extern const bcstring be_const_str_round_end;
+extern const bcstring be_const_str_round_start;
+extern const bcstring be_const_str_rtc;
+extern const bcstring be_const_str_rule;
+extern const bcstring be_const_str_run;
+extern const bcstring be_const_str_run_bat;
+extern const bcstring be_const_str_run_deferred;
+extern const bcstring be_const_str_running;
+extern const bcstring be_const_str_save;
+extern const bcstring be_const_str_save_before_restart;
+extern const bcstring be_const_str_scale_uint;
+extern const bcstring be_const_str_scan;
+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_serial;
+extern const bcstring be_const_str_set;
+extern const bcstring be_const_str_set_alternate;
+extern const bcstring be_const_str_set_auth;
+extern const bcstring be_const_str_set_bri;
+extern const bcstring be_const_str_set_chg_current;
+extern const bcstring be_const_str_set_dc_voltage;
+extern const bcstring be_const_str_set_dcdc_enable;
+extern const bcstring be_const_str_set_first_time;
+extern const bcstring be_const_str_set_height;
+extern const bcstring be_const_str_set_ldo_enable;
+extern const bcstring be_const_str_set_ldo_voltage;
+extern const bcstring be_const_str_set_light;
+extern const bcstring be_const_str_set_matrix_pixel_color;
+extern const bcstring be_const_str_set_percentage;
+extern const bcstring be_const_str_set_pixel_color;
+extern const bcstring be_const_str_set_power;
+extern const bcstring be_const_str_set_style_bg_color;
+extern const bcstring be_const_str_set_style_line_color;
+extern const bcstring be_const_str_set_style_pad_right;
+extern const bcstring be_const_str_set_style_text_font;
+extern const bcstring be_const_str_set_text;
+extern const bcstring be_const_str_set_time;
+extern const bcstring be_const_str_set_timeouts;
+extern const bcstring be_const_str_set_timer;
+extern const bcstring be_const_str_set_useragent;
+extern const bcstring be_const_str_set_width;
+extern const bcstring be_const_str_set_x;
+extern const bcstring be_const_str_set_y;
+extern const bcstring be_const_str_setbits;
+extern const bcstring be_const_str_seti;
+extern const bcstring be_const_str_setitem;
+extern const bcstring be_const_str_setmember;
+extern const bcstring be_const_str_setrange;
+extern const bcstring be_const_str_settings;
+extern const bcstring be_const_str_shared_key;
+extern const bcstring be_const_str_show;
+extern const bcstring be_const_str_sin;
+extern const bcstring be_const_str_sinh;
+extern const bcstring be_const_str_size;
+extern const bcstring be_const_str_skip;
+extern const bcstring be_const_str_solidified;
+extern const bcstring be_const_str_split;
+extern const bcstring be_const_str_sqrt;
+extern const bcstring be_const_str_srand;
+extern const bcstring be_const_str_start;
+extern const bcstring be_const_str_state;
+extern const bcstring be_const_str_static;
+extern const bcstring be_const_str_stop;
+extern const bcstring be_const_str_stop_iteration;
+extern const bcstring be_const_str_str;
+extern const bcstring be_const_str_strftime;
+extern const bcstring be_const_str_string;
+extern const bcstring be_const_str_strip;
+extern const bcstring be_const_str_strptime;
+extern const bcstring be_const_str_super;
+extern const bcstring be_const_str_sys;
+extern const bcstring be_const_str_tag;
+extern const bcstring be_const_str_tan;
+extern const bcstring be_const_str_tanh;
+extern const bcstring be_const_str_target;
+extern const bcstring be_const_str_target_search;
+extern const bcstring be_const_str_tasmota;
+extern const bcstring be_const_str_tasmota_X2Eget_light_X28_X29_X20is_X20deprecated_X2C_X20use_X20light_X2Eget_X28_X29;
+extern const bcstring be_const_str_tasmota_X2Eset_light_X28_X29_X20is_X20deprecated_X2C_X20use_X20light_X2Eset_X28_X29;
+extern const bcstring be_const_str_tcpclient;
+extern const bcstring be_const_str_tele;
+extern const bcstring be_const_str_the_X20second_X20argument_X20is_X20not_X20a_X20function;
+extern const bcstring be_const_str_time_dump;
+extern const bcstring be_const_str_time_reached;
+extern const bcstring be_const_str_time_str;
+extern const bcstring be_const_str_to_gamma;
+extern const bcstring be_const_str_tob64;
+extern const bcstring be_const_str_tolower;
+extern const bcstring be_const_str_tomap;
+extern const bcstring be_const_str_top;
+extern const bcstring be_const_str_toptr;
+extern const bcstring be_const_str_tostring;
+extern const bcstring be_const_str_toupper;
+extern const bcstring be_const_str_tr;
+extern const bcstring be_const_str_traceback;
+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_unknown_X20instruction;
+extern const bcstring be_const_str_update;
+extern const bcstring be_const_str_upper;
+extern const bcstring be_const_str_url_encode;
+extern const bcstring be_const_str_v;
+extern const bcstring be_const_str_value;
+extern const bcstring be_const_str_value_error;
+extern const bcstring be_const_str_valuer_error;
+extern const bcstring be_const_str_var;
+extern const bcstring be_const_str_w;
+extern const bcstring be_const_str_wd;
+extern const bcstring be_const_str_web_add_button;
+extern const bcstring be_const_str_web_add_config_button;
+extern const bcstring be_const_str_web_add_console_button;
+extern const bcstring be_const_str_web_add_handler;
+extern const bcstring be_const_str_web_add_main_button;
+extern const bcstring be_const_str_web_add_management_button;
+extern const bcstring be_const_str_web_send;
+extern const bcstring be_const_str_web_send_decimal;
+extern const bcstring be_const_str_web_sensor;
+extern const bcstring be_const_str_webclient;
+extern const bcstring be_const_str_webserver;
+extern const bcstring be_const_str_while;
+extern const bcstring be_const_str_widget_cb;
+extern const bcstring be_const_str_widget_constructor;
+extern const bcstring be_const_str_widget_ctor_cb;
+extern const bcstring be_const_str_widget_ctor_impl;
+extern const bcstring be_const_str_widget_destructor;
+extern const bcstring be_const_str_widget_dtor_cb;
+extern const bcstring be_const_str_widget_dtor_impl;
+extern const bcstring be_const_str_widget_editable;
+extern const bcstring be_const_str_widget_event;
+extern const bcstring be_const_str_widget_event_cb;
+extern const bcstring be_const_str_widget_event_impl;
+extern const bcstring be_const_str_widget_group_def;
+extern const bcstring be_const_str_widget_height_def;
+extern const bcstring be_const_str_widget_instance_size;
+extern const bcstring be_const_str_widget_struct_by_class;
+extern const bcstring be_const_str_widget_struct_default;
+extern const bcstring be_const_str_widget_width_def;
+extern const bcstring be_const_str_width;
+extern const bcstring be_const_str_width_def;
+extern const bcstring be_const_str_wifi;
+extern const bcstring be_const_str_wire;
+extern const bcstring be_const_str_wire1;
+extern const bcstring be_const_str_wire2;
+extern const bcstring be_const_str_wire_scan;
+extern const bcstring be_const_str_write;
+extern const bcstring be_const_str_write8;
+extern const bcstring be_const_str_write_bit;
+extern const bcstring be_const_str_write_bytes;
+extern const bcstring be_const_str_write_file;
+extern const bcstring be_const_str_write_gpio;
+extern const bcstring be_const_str_x;
+extern const bcstring be_const_str_x1;
+extern const bcstring be_const_str_y;
+extern const bcstring be_const_str_y1;
+extern const bcstring be_const_str_year;
+extern const bcstring be_const_str_yield;
+extern const bcstring be_const_str_zero;
+extern const bcstring be_const_str_zip;
diff --git a/lib/libesp32/berry/generate/be_const_strtab_def.h b/lib/libesp32/berry/generate/be_const_strtab_def.h
new file mode 100644
index 000000000..4c195c96b
--- /dev/null
+++ b/lib/libesp32/berry/generate/be_const_strtab_def.h
@@ -0,0 +1,1109 @@
+be_define_const_str(, "", 2166136261u, 0, 0, NULL);
+be_define_const_str(_X0A, "\n", 252472541u, 0, 1, &be_const_str_Unknown_X20command);
+be_define_const_str(_X20, " ", 621580159u, 0, 1, &be_const_str_geti);
+be_define_const_str(_X21_X3D, "!=", 2428715011u, 0, 2, &be_const_str_asstring);
+be_define_const_str(_X21_X3D_X3D, "!==", 559817114u, 0, 3, &be_const_str_type);
+be_define_const_str(_X23, "#", 638357778u, 0, 1, &be_const_str_CFG_X3A_X20no_X20_X27_X2A_X2Eautoconf_X27_X20file_X20found);
+be_define_const_str(_X23autoexec_X2Ebat, "#autoexec.bat", 3382890497u, 0, 13, &be_const_str_arg_size);
+be_define_const_str(_X23autoexec_X2Ebe, "#autoexec.be", 1181757091u, 0, 12, &be_const_str_file_X20extension_X20is_X20not_X20_X27_X2Ebe_X27_X20or_X20_X27_X2Ebec_X27);
+be_define_const_str(_X23display_X2Eini, "#display.ini", 182218220u, 0, 12, &be_const_str___lower__);
+be_define_const_str(_X23init_X2Ebat, "#init.bat", 3297595077u, 0, 9, &be_const_str_SERIAL_7O2);
+be_define_const_str(_X23preinit_X2Ebe, "#preinit.be", 687035716u, 0, 11, &be_const_str_SERIAL_8O2);
+be_define_const_str(_X2502d_X25s_X2502d, "%02d%s%02d", 1587999717u, 0, 10, &be_const_str_yield);
+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__global_def);
+be_define_const_str(_X25s_X2Eautoconf, "%s.autoconf", 3560383524u, 0, 11, &be_const_str_every_second);
+be_define_const_str(_X26lt_X3BError_X3A_X20apply_X20new_X20or_X20remove_X26gt_X3B, "<Error: apply new or remove>", 2855507949u, 0, 34, &be_const_str_add_driver);
+be_define_const_str(_X26lt_X3BNone_X26gt_X3B, "<None>", 2602165498u, 0, 12, &be_const_str_rand);
+be_define_const_str(_X28_X29, "()", 685372826u, 0, 2, &be_const_str__X3Cinstance_X3A_X20_X25s_X28_X25s_X2C_X20_X25s_X2C_X20_X25s_X29);
+be_define_const_str(_X2B, "+", 772578730u, 0, 1, &be_const_str_gpio);
+be_define_const_str(_X2C, ",", 688690635u, 0, 1, &be_const_str_add_cmd);
+be_define_const_str(_X2D_X2D_X3A_X2D_X2D, "--:--", 1370615441u, 0, 5, &be_const_str_AudioOutputI2S);
+be_define_const_str(_X2E, ".", 722245873u, 0, 1, NULL);
+be_define_const_str(_X2E_X2E, "..", 2748622605u, 0, 2, &be_const_str__X2Ep2);
+be_define_const_str(_X2Eautoconf, ".autoconf", 2524679088u, 0, 9, NULL);
+be_define_const_str(_X2Ebe, ".be", 1325797348u, 0, 3, &be_const_str_sinh);
+be_define_const_str(_X2Ebec, ".bec", 3985273221u, 0, 4, &be_const_str__debug_present);
+be_define_const_str(_X2Elen, ".len", 850842136u, 0, 4, NULL);
+be_define_const_str(_X2Ep, ".p", 1171526419u, 0, 2, &be_const_str_COLOR_WHITE);
+be_define_const_str(_X2Ep1, ".p1", 249175686u, 0, 3, &be_const_str_sin);
+be_define_const_str(_X2Ep2, ".p2", 232398067u, 0, 3, &be_const_str_json_fdump_map);
+be_define_const_str(_X2Esize, ".size", 1965188224u, 0, 5, &be_const_str__X2Fac);
+be_define_const_str(_X2Etapp, ".tapp", 1363391594u, 0, 5, NULL);
+be_define_const_str(_X2Ew, ".w", 1255414514u, 0, 2, &be_const_str_member);
+be_define_const_str(_X2F, "/", 705468254u, 0, 1, &be_const_str_None);
+be_define_const_str(_X2F_X2Eautoconf, "/.autoconf", 2212074393u, 0, 10, &be_const_str_set_dc_voltage);
+be_define_const_str(_X2F_X3Frst_X3D, "/?rst=", 580074707u, 0, 6, &be_const_str_AES_GCM);
+be_define_const_str(_X2Fac, "/ac", 3904651978u, 0, 3, &be_const_str_get_current_module_path);
+be_define_const_str(_X3A, ":", 1057798253u, 0, 1, &be_const_str_json_fdump);
+be_define_const_str(_X3C, "<", 957132539u, 0, 1, NULL);
+be_define_const_str(_X3C_X2Fform_X3E_X3C_X2Fp_X3E, "", 3546571739u, 0, 11, &be_const_str_atan);
+be_define_const_str(_X3C_X2Fselect_X3E_X3Cp_X3E_X3C_X2Fp_X3E, "", 1863865923u, 0, 16, NULL);
+be_define_const_str(_X3C_X3D, "<=", 2499223986u, 0, 2, &be_const_str_HTTP_POST);
+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_Wire);
+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_color);
+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_area);
+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, "