logo elektroda
logo elektroda
X
logo elektroda
Dostępna jest polska wersja

Czy wolisz polską wersję strony elektroda?

Nie, dziękuję Przekieruj mnie tam

Berry scripting for various IoT platforms - tutorial for OBK new script integration part 1

p.kaczmarek2  13 4536 Cool? (+7)
📢 Listen (AI):

TL;DR

  • Berry scripting lands in OpenBeken for IoT modules like BK7231, W800/W600, ESP32, BL602, LN882, Realtek, plus the Windows simulator.
  • Scripts run from LittleFS modules and use runCmd, setInterval/setTimeout, addEventHandler, and HTTP callbacks to control relays, react to buttons, and build web UI.
  • Berry’s core is under 40KiB and it can run on less than 4KiB heap, with examples covering 500 ms blinking, 1000 ms delays, and MQTT/Home Assistant integration.
  • ENABLE_OBK_BERRY must be enabled, and stack sizes may need manual adjustment because some OBK features may be disabled to keep binaries small.
Generated by the language model.
OpenBeken simulator with debugging console and BL0942 schematic
Berry is a lightweight scripting language designed for embedded system. It features dynamically typed, one-pass compiler and interpreter with core’s code size is less than 40KiB which can run on less than 4KiB heap. Thanks to latest OBK integration, Berry can now run on most of new IoT modules, including BK7231, W800/W600, ESP32, BL602, LN882, Realtek. It can also run in OBK Windows simulator, so you can try out Berry easily, along with full MQTT and Home Assistant integration.

For more information about Berry, please see Berry documentation:
https://berry.readthedocs.io/en/latest/index.html

Now let's focus on running Berry in OBK. Currently, there are two options:
Option 1: you can just use OpenBeken Simulator to try Berry on Windows, just get binaries here: https://github.com/openshwprojects/OpenBK7231T_App/releases
Screenshot with a download link for OBK Simulator for Windows
Option 2: You can use only builds (no toolchain required) to enable Berry for the platform of your choice, follow this tutorial. Keep in mind that on some platforms you might need to disable some other features in order to keep binary size small enough to run. This is because OBK comes by default with most of the features enabled, so each binary has TuyaMCU driver, LED driver, WS2812 driver with animations, and even Tasmota JSON support, and you most likely will not this kind of thing. So, edit obk_config.h to suit your needs. Just remember - for Berry, you need to enable ENABLE_OBK_BERRY define.
Futhermore, the stack sizes may not be adjusted for Berry currently, so you might need to increase them on your own. There is also still room for optimization in Berry code, for example, some event handlers could be more or less delayed to avoid large stack requirement. This is still subject to change in future.

This tutorial will be based on OBK Windows Simulator, so anyone can run it, even with no IoT devices.
Screenshot of OpenBeken simulator showing a circuit diagram with elements like a bulb and a BL0942 chip, and a terminal log window.
Don't forget to get OBK simulator samples here:
https://github.com/openshwprojects/obkSimulator
They will be used here for demonstration purposes.

I also assume that you know more or less how to run OBK Simulator - it creates a simulation window and virtual device page on your local IP, port 80. For more information, see related Simulator topic.

First Berry steps
Let's start by executing some simple Berry commands in OBK command line:

berry print("Hello, Berry")

Berry command tool interface displaying the result of the command berry print(Hello, Berry).
The same could be done in the Web App console:
Screenshot of logs showing execution of the command berry print('Hello, Berry') in the OpenBeken environment.
This way you can test various berry commands, for example, expressions:

berry print("Hello " + str(5+2*2))

Screenshot of the Windows Fake BL0942 interface with Berry commands.

First Berry commands
The most simple way to call OBK commands from Berry is "runCmd" command.
Commands should be taken from here:
https://github.com/openshwprojects/OpenBK7231T_App/blob/main/docs/commands.md
For example, you call setChannel from Berry to set new channel value. In OBK, this can for example set relay state, along with whole MQTT publish and state update:

berry runCmd("setChannel 1 1")

Screenshot of the Berry command line tool interface with a command entered.
You can use the same approach to run text commands as well:

berry runCmd("MQTTHost 192.168.0.213")

Similary, you can use OBK publish commands to publish your data to Home Assistant:


Berry script files
Main Berry scripts should reside within Berry modules. Berry modules can be created in LittleFS file system:



Let's start by making simplest module. Call it autoexec.be. It will run on each device startup.

autoexec = module('autoexec')

# Add functions to the module
autoexec.myInit = def()
   setChannel(1, 42)
end

# Call function on first load
autoexec.myInit()

# Berry modules must return the module object
return autoexec

File management interface with open script editor in OBK
For faster prototyping, you can use "Save, Reset SVM and run file" button. This will also attempt to clear device state to simulate a reboot, but may not be always reliable.



Script execution over time
OBK features two commands that allows you to run scripts over time:
- setTimeout - runs commands once
- setInterval - runs command repeatedly
With setInterval, you can make a simple "blink LED" (or a relay, or anything) demo:

autoexec = module('autoexec')

autoexec.myToggle= def()
   runCmd("toggleChannel 1")
end

setInterval(autoexec.myToggle, 500)

return autoexec

Circuit diagram using a WB3S module connected to two bulbs.
The same could be done with setTimeout, if needed:

autoexec = module('autoexec')

autoexec.myToggle= def()
   runCmd("toggleChannel 1")
   setTimeout(autoexec.myToggle, 500)
end

autoexec.myToggle()

return autoexec



Reacting to events - buttons
Berry can react to OpenBeken events. For example, you can use it with Btn_ScriptOnly button. Set a Btn_ScriptOnly role for given pin, let's say, 14, and try following code:

autoexec = module('autoexec')


autoexec.myToggle= def()
   runCmd("toggleChannel 1")
   runCmd("toggleChannel 2")
end

addEventHandler("OnClick", 8, autoexec.myToggle);

return autoexec

For the demonstration purposes, I've put two relays ("bulbs") on channel 1 and channel 2:
Circuit diagram of a system with bulbs and WBS5 microcontroller

Reacting to events - channels
Similar approach can be taken to, for example, turn off relay after some time. In this case, we'll catch the situation when channel becomes 1 and set it back to 0 after some time. Keep in mind that for this demo I've set back the PWM2 pin button role to Btn, so it has automatic interaction with channel 1. So, channel 1 toggle is handled by OBK internally, as usual.

autoexec = module('autoexec')

autoexec.myToggle= def()
   runCmd("setChannel 1 0")
end

autoexec.myDelay= def()
   setTimeout(autoexec.myToggle, 1000)
end

addEventHandler("Channel1", 1, autoexec.myDelay);

return autoexec

Electrical circuit diagram with two bulbs connected to a WBS5 module.
The code could be simplified by adding inline functions:

autoexec = module('autoexec')

autoexec.myToggle= def()
   runCmd("setChannel 1 0")
end

addEventHandler("Channel1", 1, def()
   setTimeout(autoexec.myToggle, 1000)
end);

return autoexec

and even futher:

autoexec = module('autoexec')

addEventHandler("Channel1", 1, def()
   setTimeout(def()
       runCmd("setChannel 1 0")
   end, 1000)
end);

return autoexec


Stopping and running intervals
setInterval returns a handle that can be later used to stop the interval. You can store it in a global variable and call "cancel" later. The following example demonstrates a stoppable setInterval demo where first button press starts then interval that blinks LEDs, and second button press stops it.

autoexec = module('autoexec')

g_handle = 0;

autoexec.myToggle= def()
   if g_handle == 0
        g_handle = setInterval(def() 
             runCmd("toggleChannel 1")
             runCmd("toggleChannel 2")
        end, 200 )
     else 
           cancel(g_handle)
           g_handle = 0
      end
end

addEventHandler("OnClick", 8, autoexec.myToggle);

return autoexec

Circuit diagram with WB3S module and bulbs


Calling module functions from outside
Keep in mind that you can simply use Berry modules anywhere inside OBK. Let's consider simplified version of mentioned module:

autoexec = module('autoexec')

g_handle = 0;

autoexec.myToggle= def()
   if g_handle == 0
        g_handle = setInterval(def() 
             runCmd("toggleChannel 1")
             runCmd("toggleChannel 2")
        end, 200 )
     else 
           cancel(g_handle)
           g_handle = 0
      end
end

return autoexec

Once you have it in LFS, you can just run OBK command:

berry import autoexec; autoexec.myToggle()

and it will correctly toggle the blink interval.
Command Tool console interface with Berry command.


Direct command handlers
There are more ways to call Berry functions from outside. For example, you can just create your own command handler in Berry:

autoexec = module('autoexec')

g_handle = 0;

autoexec.myToggle= def()
   if g_handle == 0
        g_handle = setInterval(def() 
             runCmd("toggleChannel 0")
             runCmd("toggleChannel 1")
             runCmd("toggleChannel 2")
        end, 200 )
     else 
           cancel(g_handle)
           g_handle = 0
      end
end

addEventHandler("OnCmd", "MyCmd", autoexec.myToggle)

return autoexec

Keep in mind that now you can run this command from anywhere - even from MQTT!
OpenBeken simulator interface with a command input field and wiring diagram.


Direct command arguments
Commands can have arguments that are also passed to Berry. Arguments are strings by default, so you need to cast them to int to use them as a number. In this example, we'll modify the blinking command to include single argument, which is a blink interval. In order to convert it to string, I've used int(del) function.

autoexec = module('autoexec')

g_handle = 0;

autoexec.myToggle= def(del)
   if g_handle == 0
        g_handle = setInterval(def() 
             runCmd("toggleChannel 0")
             runCmd("toggleChannel 1")
             runCmd("toggleChannel 2")
        end, int(del))
     else 
           cancel(g_handle)
           g_handle = 0
      end
end

addEventHandler("OnCmd", "MyCmd", autoexec.myToggle)

return autoexec

The usage is very simple:
Screenshot of the OBK Simulator command tool interface showing a text box with the command MyCmd 150 and a Submit button.
Of course, when in doubt, you can just print out some debug information:
Screenshot of editing an autoexec.be script with code in the user interface.
Screenshot of command line tool console for Berry in OBK simulator.


Showing information on state section
OpenBeken features a main page with a state section that is automatically refreshed in background.


autoexec = module('autoexec')

g_handle = 0;

autoexec.myToggle= def(del)
   if g_handle == 0
        print("Will runinterval with del "+str(del));
        g_handle = setInterval(def() 
             runCmd("toggleChannel 0")
             runCmd("toggleChannel 1")
             runCmd("toggleChannel 2")
        end, int(del))
     else 
          print("Will stop interval")
           cancel(g_handle)
           g_handle = 0
      end
end

autoexec.myShow= def(request)
     poststr(request, "<h1>Hello Berry!</h1>") 
     poststr(request, "<h5>Interval ID is " + str(g_handle)+"</h1>") 
end

addEventHandler("OnHTTP", "state", autoexec.myShow)
addEventHandler("OnCmd", "MyCmd", autoexec.myToggle)

return autoexec

Screenshot of a simulation application displaying power data and relay status.
Interval ID will be 0 when it's inactive.
Screenshot of a simulation application interface for the Berry scripting language.



Access to OBK variables - power metering
OpenBeken has some legacy variables that were used before Berry introduction. They can be seen here:
https://github.com/openshwprojects/OpenBK7231T_App/blob/main/docs/constants.md
In Berry, you can access them with getVar function.
Here's a simple BL0942/BL0937 readout demo:

autoexec = module('autoexec')

autoexec.myShow= def(request)
     v = getVar("$voltage");
     poststr(request, "<h3>Berry voltage " + str(v)+"</h3>") 
     c = getVar("$current");
     poststr(request, "<h3>Berry current " + str(c)+"</h3>") 
     p = getVar("$power");
     poststr(request, "<h3>Berry power " + str(p)+"</h3>") 
end

addEventHandler("OnHTTP", "state", autoexec.myShow)

return autoexec

Screenshot of OpenBeken Simulator showing a circuit schematic with voltage, current, and power measurements.
Values are correctly displayed on the main page:
User interface of a simulator with voltage, current, and power data.
Following example can be expanded with conditionals. You can use if block to check voltage value.

autoexec = module('autoexec')

autoexec.myShow= def(request)
     v = getVar("$voltage");
     poststr(request, "<h3>Berry voltage " + str(v)+"</h3>") 
     if v > 245 
          poststr(request, "<h3 style='color:red'>OVERVOLTAGE ALARM</h3>") 
    elif v < 210 
          poststr(request, "<h3 style='color:red'>UNDERVOLTAGE ALARM</h3>");
     end
     c = getVar("$current");
     poststr(request, "<h3>Berry current " + str(c)+"</h3>") 
     p = getVar("$power");
     poststr(request, "<h3>Berry power " + str(p)+"</h3>") 
end

addEventHandler("OnHTTP", "state", autoexec.myShow)

return autoexec

Now, let's set voltage to 260 and see what happens:
Diagram of BL0942 simulator circuit showing voltage, current, power, and frequency values.
The error message is displayed correctly:
Screenshot showing electrical parameters with an overvoltage alarm.

Extra sample - refresh counter
Following script will counter the number of automatic refreshes done by OBK state page segment:

autoexec = module("autoexec")

cnt = 0;

addEventHandler("OnHTTP", "state", def(request)
     poststr(request, "<h3>Refresh counter " + str(cnt) + "</h3>") 
     cnt = cnt + 1
end)

return autoexec

Screenshot of an interface showing a refresh counter and a toggle switch.



Extra sample - loop logic and power check
The following sample was requested several times by users. This is a simple mechanism used to turn off relay when power consumption is below given threshold for given time. This can be used to detect when charging is finished.
In order to implement it, I've created a simple repeating interval called "my Logic", where I access current power value and compare it against predefined threshold, in this case, 1W. If it's below 1W, I count the number of loops, and if it reaches 5 (5 seconds, because one loop is one second here) I turn off the relay.

autoexec = module("autoexec")

loopsLowPower = 0;

def myLogic()
      p = getVar("$power");
      print("power is " +str(p));

      if p < 1
         loopsLowPower  += 1
         if loopsLowPower  > 5 
           runCmd("POWER OFF");
         end
      else
          loopsLowPower  = 0;
      end
end

setInterval(myLogic, 1000);

return autoexec

The following sample can be extended by, for example, moving constants to text fields:

autoexec = module("autoexec")

loopsLowPower = 0;

def myLogic()
      p = getVar("$power");
      print("power is " +str(p));
      
      minPower = getChannel(5);
      if p < 1
         loopsLowPower  += 1
         if loopsLowPower  > 5 
           runCmd("POWER OFF");
         end
      else
          loopsLowPower  = 0;
      end
end

runCmd("setChannelType 5 TextField")
runCmd("setChannelLabel 5 MinPower");

setInterval(myLogic, 1000);

return autoexec

Result:
Screenshot of an interface simulating a channel test with an option to change MinPower value.

Access to OBK variables - time variables
First start NTP driver. Once it's running, you will be able to access current time data:
Screenshot showing the command input tool in the WinTest application.
Try following script:


autoexec = module('autoexec')

autoexec.myShow= def(request)
     h = getVar("$hour");
     m = getVar("$minute");
     poststr(request, "<h1>" + str(h)+":" + str(m)+"</h1>") 
end

addEventHandler("OnHTTP", "state", autoexec.myShow)

return autoexec

It will print NTP hour/minute on the main panel:
OBK simulator interface showing device status and electrical parameters.



Custom HTML fields
HTTP callback also allows you to create custom HTML fields. They can store any kind of data that is later processed by Berry. You can use getVar to access GET variables as well. The input field, however, can be tricky. This is becaue state section is refreshed automatically, so you'd lose the data you type. That's why there is another callback - called "prestate" that runs before state div. So field is created in prestate, and display in the state.


autoexec = module('autoexec')
name = "Unknown";

autoexec.myPre= def(request)
     other = getVar("name");
      if other != nil
        name = other;       
     end
      poststr(request, "<form method='GET'>Name: <input name='name'><input type='submit'></form>")
end


autoexec.myState= def(request)
     poststr(request, "<h1> Hello, " + name+"!</h1>") 
end

addEventHandler("OnHTTP", "prestate", autoexec.myPre)
addEventHandler("OnHTTP", "state", autoexec.myState)


return autoexec

Screenshot of a form with a field to enter a name and a Submit button, below is the text Hello, Unknown!
OBK Simulator user interface with a text field and Submit button

Related reading
For more information on OBK events (button handling, etc), clock events (NTP, etc), see autoexec.bat samples. They are not in Berry, but they can still give some insights into OBK possibilities:
https://github.com/openshwprojects/OpenBK7231T_App/blob/main/docs/autoexecExamples.md

That's all for now
This is how you can create more advanced scripts in OBK. Let me know if you have any futher suggestions or ideas.
Soon I will post tutorial part 2, which will cover more advenced HTTP stuff, TuyaMCU integration and data processing.
Just please keep in mind that Berry integration has been so far mostly tested with self tests ( https://www.elektroda.com/rtvforum/topic4109775.html ) and in Simulator, so any testing is welcome. Let me know if you try to run some of my scripts on physical devices! Any testers available - @divadiow maybe? And special thanks for @niterian for initial Berry demo.

About Author
p.kaczmarek2
p.kaczmarek2 wrote 14238 posts with rating 12144 , helped 647 times. Been with us since 2014 year.

Comments

divadiow 14 Apr 2025 10:43

Fantastic stuff. I am not familiar with Berry though I have heard it mentioned in relation to Tasmota. I'll read this guide in earnest again and hopefully try some things on actual devices in due cour... [Read more]

p.kaczmarek2 14 Apr 2025 14:14

Thank you. If you have some spare time, you can just try running berry "Hello world" or simplest Berry OBK http page addon for the time being. Just to see if it works on any physical devices. The integration... [Read more]

divadiow 14 Apr 2025 16:32

https://github.com/openshwprojects/OpenBK7231T_App/actions/runs/14448069041 😭 [Read more]

p.kaczmarek2 14 Apr 2025 16:46

Probably makefile stuff. Files needs to be added by hand. BK7231 scans for files recursively, so it works for BK, but not for others. Added after 5 [minutes]: Ah, there was also a missing header,... [Read more]

divadiow 14 Apr 2025 16:49

ok. yes. was about to test W800 makefile. feel free to cancel my queued/stuck until you're at a point where I should update my branch with your latest changes [Read more]

p.kaczmarek2 14 Apr 2025 17:52

I think BK7231 Easy UART flasher should be also able to download from Pull Requests... Added after 57 [minutes]: BK7238 test: https://obrazki.elektroda.pl/7075937700_1744645711_bigthumb.jpg... [Read more]

divadiow 14 Apr 2025 17:53

BK-T https://obrazki.elektroda.pl/1282162100_1744645996_thumb.jpg https://obrazki.elektroda.pl/9459347800_1744645931_thumb.jpg [Read more]

p.kaczmarek2 14 Apr 2025 18:00

We need to dig into makefiles so it can build on more platforms, for example, on ESP32 [Read more]

divadiow 14 Apr 2025 18:02

is a divide by zero also a worthy test to be sure it errors gracefully without killing device or is that not a valid concern? berry print("Hello " + str(5+1/0)) https://obrazki.elektroda.pl/6547... [Read more]

p.kaczmarek2 14 Apr 2025 18:21

Nice, it seems that Berry handles it well internally. [Read more]

JacekCz 15 Apr 2025 11:05

. What are the motives behind the new language ? Practically comparable to Lua, and this one has a long-standing presence. Also prone to miniaturisation Somewhat partial "C-ness" in syntax and "Pascal-ness"... [Read more]

p.kaczmarek2 15 Apr 2025 11:31

@jacekcz I had initially planned LUA myself, as I know it and have integrated it with C/C++ many times before, but then one contributor recommended Berry and pointed out that it is potentially lighter... [Read more]

p.kaczmarek2 19 Nov 2025 23:50

I am integrating more functions with Berry. For example, here's an interesting sample that creates a list in Berry (probably not yet finished, but passes basic checks): int be_gmtime(bvm *vm) { struct... [Read more]

FAQ

TL;DR: Berry gives OpenBeken a lightweight scripting layer with a core under 40 KiB and operation on under 4 KiB heap. As the tutorial puts it, it is "lightweight" and now runs across BK7231, W800/W600, ESP32, BL602, LN882, and Realtek targets. This FAQ helps OBK users script automation, HTTP pages, timers, and event handlers without writing full firmware code. [#21517768]

Why it matters: It turns OpenBeken from configurable firmware into a scriptable IoT platform for fast prototyping, device logic, and UI extensions.

Option What it is Hardware required Best use
OBK Windows Simulator Desktop simulator with local web UI No Learning, debugging, HTTP/MQTT tests
OBK build with Berry enabled Firmware build with ENABLE_OBK_BERRY Yes Real-device automation and deployment
setInterval Repeating timer No extra hardware Blinkers, polling, recurring logic
setTimeout One-shot timer No extra hardware Delayed actions, self-rescheduling loops

Key insight: The thread shows that Berry is most valuable when you combine three OBK hooks: commands, events, and HTTP callbacks. That combination lets one small autoexec.be module automate relays, react to buttons, and render live status on the main page.

Quick Facts

  • Berry is described as having a core code size below 40 KiB and running on less than 4 KiB heap, which is why it fits small embedded targets better than heavier scripting options. [#21517768]
  • The tutorial names these current OBK targets for Berry: BK7231, W800/W600, ESP32, BL602, LN882, and Realtek, plus the Windows Simulator for desktop testing. [#21517768]
  • Timed examples in the thread use concrete intervals of 200 ms, 500 ms, and 1000 ms, covering fast blinking, regular toggles, and delayed shutoff logic. [#21517768]
  • The voltage alarm demo flags overvoltage above 245 V and undervoltage below 210 V, then prints a warning in the OBK state section. [#21517768]
  • The power-check automation turns a relay off when power stays below 1 W for more than 5 loops at 1-second intervals, effectively about 5 seconds. [#21517768]

What is Berry scripting in OpenBeken (OBK), and why is it useful for embedded IoT devices like BK7231, ESP32, W800, BL602, LN882, and Realtek modules?

Berry scripting in OpenBeken is a lightweight embedded scripting layer that lets you add device logic without rebuilding full firmware. It is useful because the thread states Berry’s core is under 40 KiB and can run on less than 4 KiB heap, while OBK integration targets BK7231, W800/W600, ESP32, BL602, LN882, and Realtek modules. That makes it practical for timers, button logic, MQTT actions, HTTP UI output, and quick experiments on constrained IoT hardware. [#21517768]

How do I enable Berry support in OpenBeken builds, and which settings in obk_config.h and stack sizes usually need to be adjusted?

Enable Berry by editing obk_config.h and turning on ENABLE_OBK_BERRY. The tutorial also warns that you may need to disable other features to keep the binary small enough, because default OBK builds include items like TuyaMCU, LED, WS2812 animations, and Tasmota JSON support. Stack sizes may also need manual increases, because current defaults are not always sized for Berry handlers and HTTP callbacks. [#21517768]

What is the OpenBeken Windows Simulator, and how do I use it to test Berry scripts without any physical IoT hardware?

The OpenBeken Windows Simulator is a desktop build that runs OBK in Windows and exposes a simulation window plus a device web page on your local IP, port 80. Use it in three steps: 1. download the simulator binaries and sample files, 2. launch the simulator, 3. run Berry commands in the OBK console or Web App. The author built the tutorial around this path so anyone can test Berry without physical modules. [#21517768]

How do I run my first Berry commands in OBK from the command line or Web App console, such as printing text or evaluating expressions?

Run them with the berry command in either the OBK command line or the Web App console. The first examples are berry print("Hello, Berry") and berry print("Hello " + str(5+2*2)), which show plain output and expression evaluation. A later test also shows divide-by-zero does not crash the device; it appears Berry handles that error internally. [#21517768]

What's the simplest way to call OpenBeken commands from Berry, including actions like setChannel, toggleChannel, MQTT host setup, and publishing to Home Assistant?

The simplest method is runCmd(), which sends normal OBK text commands from Berry. The thread shows runCmd("setChannel 1 1") for channel control and runCmd("MQTTHost 192.168.0.213") for MQTT setup. It also notes that using OBK channel commands triggers normal side effects, including relay state updates and MQTT publishing, which makes Home Assistant integration straightforward without separate code paths. [#21517768]

How do I create and use an autoexec.be module in LittleFS so a Berry script runs automatically on every OpenBeken device startup?

Create an autoexec.be module in LittleFS and return the module object at the end. "LittleFS is an embedded file system that stores small files in flash, supports modules like autoexec.be, and lets OBK load scripts at startup without embedding them directly in firmware." In the example, autoexec.myInit() sets channel 1 to 42 on boot, and the author recommends the “Save, Reset SVM and run file” button for faster testing. [#21517768]

Which approach should I use in Berry for timed actions in OBK: setTimeout, setInterval, or a self-rescheduling timeout loop?

Use setInterval for repeating jobs, setTimeout for one delayed action, and a self-rescheduling timeout when you want repeat logic with explicit requeue control. The tutorial demonstrates blinking with setInterval(..., 500) and the same behavior with setTimeout that calls itself again after 500 ms. Choose setInterval for simple polling and blinking, and choose self-rescheduling timeouts when each cycle should decide whether to continue. [#21517768]

How can I react to OpenBeken events in Berry, such as button clicks with Btn_ScriptOnly, channel changes, OnCmd handlers, and HTTP callbacks?

React with addEventHandler() and bind a Berry function to the OBK event name plus its parameter. "Btn_ScriptOnly is a button role in OpenBeken that forwards button actions to scripts instead of built-in relay logic, letting Berry decide what happens on each press." The thread shows OnClick for a button, Channel1 for state changes, OnCmd for custom commands like MyCmd, and OnHTTP for state or prestate page rendering. [#21517768]

What is the best way to start and stop a repeating Berry interval in OBK using a saved handle and cancel()?

Save the return value from setInterval() in a global handle, then pass that handle to cancel() when you want to stop it. The example uses g_handle = 0 as the inactive state, starts a 200 ms blink loop on first press, and cancels it on second press. That pattern is clean, reversible, and easy to trigger from buttons, commands, or other event handlers. [#21517768]

How do I call Berry module functions from outside the script in OpenBeken, for example with berry import autoexec; autoexec.myToggle() or a custom OnCmd command?

Import the module and call its function directly, or expose that function through an OnCmd event handler. The thread gives the exact console form berry import autoexec; autoexec.myToggle() and also shows addEventHandler("OnCmd", "MyCmd", autoexec.myToggle) for a named external command. That second method is especially useful because the author notes you can trigger it from MQTT as well. [#21517768]

Why are direct command arguments passed to Berry as strings in OpenBeken, and how should I convert and debug them safely?

Direct command arguments arrive as strings, so convert them before numeric use. The tutorial explicitly says command arguments are strings by default and demonstrates int(del) before using the value as an interval for setInterval. For safe debugging, print the received argument with print() first, then convert it, especially when testing commands like MyCmd 250 or when invalid input may reach the handler. [#21517768]

How can I display custom information on the OpenBeken main page state section with Berry, including HTML output, refresh counters, and live status text?

Use an OnHTTP handler for the state section and write HTML with poststr(request, ...). The examples render headings, interval status text, voltage and power readouts, and a refresh counter that increments on each automatic state refresh. For user input, the thread uses a second callback, prestate, because the normal state section refreshes automatically and would otherwise wipe text typed into a form. [#21517768]

How do I read OpenBeken legacy variables from Berry with getVar, such as $voltage, $current, $power, $hour, and $minute, and use them for alarms or automation?

Read them with getVar("$name"), then branch or display the returned value. The tutorial shows $voltage, $current, and $power on the state page, adds alarms above 245 V and below 210 V, and uses $power in a 1 W cutoff script that turns a relay off after about 5 seconds of low consumption. For time variables, start the NTP driver first, then read $hour and $minute. [#21517768]

Berry vs Lua for OpenBeken and microcontrollers: what were the motives for choosing Berry, and how do they compare in memory usage, performance, and ease of integration?

OpenBeken chose Berry mainly because contributors believed it could be lighter than Lua on small microcontrollers. The author says he originally planned Lua, but Berry was recommended as potentially smaller, and Berry’s own documentation argues Lua may still be too large for some 32-bit MCUs with limited memory. The same post also notes Berry borrows heavily from Lua’s design, so syntax and embedding concepts stay familiar while targeting lower resource use. [#21519828]

Why does Berry build or compilation support differ between BK7231, BK7238, W800, and ESP32 in OpenBeken, and what Makefile, missing-header, or workflow issues need to be fixed?

Support differs because some platforms do not pull Berry source files automatically from the tree. The thread explains BK7231 scans files recursively, so it built, while other targets needed Berry directories added manually to the Makefile. A missing header also broke ESP32 with an implicit-function-declaration error, and the workflow file needed review. After fixes, the author reported BK7238 tests working, while ESP32 still needed more Makefile work. [#21518954]
Generated by the language model.
%}