Berry Berry Scripting Language is now included in all Tasmota32 builds for ESP32 microcontrollers, offering an ultra-lightweight dynamically typed scripting language for embedded devices. The language supports advanced automations, drivers, and animations, with a REPL console and Visual Studio Code extension for development. Berry is optimized for low RAM usage and supports PSRAM on ESP32. Berry Scripting Language ~ berry-scripting-language Berry Scripting is included in all tasmota32 builds. It is NOT supported on ESP82xx If you plan to code in Berry, you should enable define USE BERRY DEBUG which will give you much more details when coding If you want to use Generative AI to generate Berry code, it is highly suggested to use claude.ai https://claude.ai/ and use the Markdown Language Reference https://tasmota.github.io/docs/ media/BERRY LANGUAGE REFERENCE.txt . This files consumes ~6000 input tokens. Useful resources: - First time user of Berry: Berry Introduction in 20 minutes of less ../Berry-Introduction/ - Language fast reference PDF 7 pages Berry Short manual https://tasmota.github.io/docs/ media/berry short manual.pdf - Full language documentation The Berry Script Language Reference Manual https://berry.readthedocs.io/en/latest/source/en/Reference.html - Tasmota extension of Berry, see below - Full examples in the Berry Cookbook ../Berry-Cookbook/ If you're new to Berry, have a look at Berry Introduction in 20 minutes of less ../Berry-Introduction/ Introduction to Berry ~ introduction-to-berry Berry is the next generation scripting for Tasmota. It is based on the open-source Berry project, delivering an ultra-lightweight dynamically typed scripting language designed for lower-performance embedded devices. Reference sheet Download Berry Short Manual https://tasmota.github.io/docs/ media/berry short manual.pdf to get a list of basic functions and capabilities of Berry language Berry Scripting allows simple and also advanced extensions of Tasmota, for example: - simple scripting - advanced rules, beyond what is possible with native rules - advanced automations Berry Scripting takes it one step further and allows to build dynamic extensions to Tasmota, that would previously require native code: - build light animations - build I 2C drivers - build complete Tasmota drivers - integrate native libraries like lvgl see LVGL ../LVGL/ About the Berry language ~ about-the-berry-language Berry has the following advantages: - Lightweight: A well-optimized interpreter with very little resources. Ideal for use in microprocessors. - Fast: optimized one-pass bytecode compiler and register-based virtual machine. - Powerful: supports imperative programming, object-oriented programming, functional programming. - Flexible: Berry is a dynamic type script, and it's intended for embedding in applications. It can provide good dynamic scalability for the host system. - Simple: simple and natural MicroPython-eque syntax, supports garbage collection and easy to use FFI foreign function interface . - RAM saving: With compile-time object construction, most of the constant objects are stored in read-only code data segments, so the RAM usage of the interpreter is very low when it starts. Tasmota Port ~ tasmota-port Berry Scripting in only supported on Tasmota32 for ESP32. The RAM usage starts at ~10KB and will be later optimized. Berry uses PSRAM on ESP32 if available PSRAM is external RAM attached to ESP32 via SPI, it is slower but larger than internal RAM. Quick Start ~ quick-start Click on Configuration then Berry Scripting Console and enjoy the colorful Berry console, also called REPL Read-Eval-Print-Loop . Drag the bottom corner of each screen to change its size The console is not designed for big coding tasks but it's recommended to use a code editor when dealing with many, many lines of code. An extension for Visual Studio Code exists to make writing Berry scripts even easier with colored syntax. Download the entire folder https://github.com/berry-lang/berry/tree/master/tools/plugins/vscode/ and copy to VSCode extensions folder. REPL Console ~ repl-console Try typing simple commands in the REPL. Since the input can be multi-lines, press Enter twice or click "Run" button to run the code. Use Up and Down to navigate through history of previous commands. 1+1 2 2.0/3 0.666667 print 'Hello Tasmota ' Hello Tasmota Note: Berry's native print command displays text in the Berry Console and in the Tasmota logs. To log with finer control, you can also use the log function which will not display in the Berry Console. print 'Hello Tasmota ' log 'Hello again' Hello Tasmota Meanwhile the Tasmota log shows: tasmota.cmd "Dimmer 60" {'POWER': 'ON', 'Dimmer': 60, 'Color': '996245', 'HSBColor': '21,55,60', 'Channel': 60, 38, 27 } The light is bright Save your Scripts ~ save-your-scripts Berry can autostart your scripts. See a short description in the Section about the filesystem: https://tasmota.github.io/docs/UFS/ autoexecbe Your can use the Filemanager to edit or save files with your berry scripts. Iterate without rebooting ~ iterate-without-rebooting Since v13.0.0.1 you can restart the entire Berry VM with a click in the Berry console. This feature requires to compile with define USE BERRY DEBUG which is anyways highly recommended when coding in Berry. Be aware that restarting the Berry VM loses all context, and may generate negative side effects that we haven't yet identified. When restarting the VM, autoexec.be is ran again. Instead of using the Web UI, you can also use the BrRestart command which does not require define USE BERRY DEBUG . Lights and Relays ~ lights-and-relays Berry provides complete support for Relays and Lights. You can control individual Relays or lights with tasmota.get power and tasmota.set power . tasmota.get power returns an array of booleans representing the state of each relays and light light comes last . tasmota.set power relay, onoff changes the state of a single relay/light. 2 relays and 1 light tasmota.get power false, true, false tasmota.set power 0, true true tasmota.get power true, true, false For light control, light.get and light.set accept a structured object containing the following arguments: | Attributes | Details | |---|---| | power | boolean Turns the light off or on. Equivalent to tasmota.set power . When brightness is set to 0 , power is automatically set to off. On the contrary, you need to specify power:true to turn the light on. | | bri | int range 0..255 Set the overall brightness. Be aware that the range is 0..255 and not 0..100 as Dimmer. | | hue | int 0..360 Set the color Hue in degree, range 0..360 0=red . | | sat | int 0..255 Set the color Saturation 0 is gray . | | ct | int 153..500 Set the white color temperature in mired, ranging from 153 cold white to 500 warm white | | rgb | string 6 hex digits Set the color as hex RRGGBB , changing color and brightness. | | channels | array of int, ranges 0..255 Set the value for each channel, as an array of numbers | When setting attributes, they are evaluated in the following order, the latter overriding the previous: power , ct , hue , sat , rgb , channels , bri . set to yellow, 25% brightness light.set {"power": true, "hue":60, "bri":64, "sat":255} {'bri': 64, 'hue': 60, 'power': true, 'sat': 255, 'rgb': '404000', 'channels': 64, 64, 0 } set to RGB 000080 blue 50% light.set {"rgb": "000080"} {'bri': 128, 'hue': 240, 'power': true, 'sat': 255, 'rgb': '000080', 'channels': 0, 0, 128 } set bri to zero, also powers off light.set {"bri": 0} {'bri': 0, 'hue': 240, 'power': false, 'sat': 255, 'rgb': '000000', 'channels': 0, 0, 0 } changing bri doesn't automatically power light.set {"bri": 32, "power":true} {'bri': 32, 'hue': 240, 'power': true, 'sat': 255, 'rgb': '000020', 'channels': 0, 0, 32 } set channels as numbers purple 12% light.set {"channels": 32,0,32 } {'bri': 32, 'hue': 300, 'power': true, 'sat': 255, 'rgb': '200020', 'channels': 32, 0, 32 } Rules ~ rules The rule function have the general form below where parameters are optional: python def function name value, trigger, msg end | Parameter | Description | |---|---| value | The value of the trigger. Similar to %value% in native rules. | trigger | string of the trigger with all levels. Can be used if the same function is used with multiple triggers. | msg | map Berry structured object of the message, decoded from JSON. If JSON was invalid, it contains the original string | Dimmer rule Define the function and add a rule to Tasmota where the function runs if Dimmer value is more than 50 python def dimmer over 50 print "The light is bright" end tasmota.add rule "Dimmer 50", dimmer over 50 tasmota.cmd "Dimmer 30" {'POWER': 'ON', 'Dimmer': 30, 'Color': '4D3223', 'HSBColor': '21,55,30', 'Channel': 30, 20, 14 } tasmota.cmd "Dimmer 60" {'POWER': 'ON', 'Dimmer': 60, 'Color': '996245', 'HSBColor': '21,55,60', 'Channel': 60, 38, 27 } The light is bright The same function can be used with multiple triggers. If the function to process an ADC input should be triggered both by the tele/SENSOR message and the result of a Status 10 command: tasmota.add rule "ANALOG A1", rule adc 1 tasmota.add rule "StatusSNS ANALOG A1", rule adc 1 Or if the same function is used to process similar triggers: python import string def rule adc value, trigger var i=string.find trigger," A" var tr=string.split trigger,i+2 var adc=number tr 1 print "value of adc",adc," is ",value end tasmota.add rule "ANALOG A1",rule adc tasmota.add rule "ANALOG A2",rule adc Another way to address the same using anonymous functions created dynamically python def rule adc adc, value print "value of adc",adc," is ",value end tasmota.add rule "ANALOG A1", def value rule adc 1,value end tasmota.add rule "ANALOG A2", def value rule adc 2,value end Multiple triggers AND logic ~ multiple-triggers-and-logic It is possible to combine multiple triggers in a AND logic as an array: tasmota.add rule "ANALOG A1 300","ANALOG A1<500" , def values rule adc in range 1,values end 300 < ANALOG A1 < 500 Triggers can be of different types too: tasmota.add rule "ANALOG A1 300","BME280 Temperature 28.0" , def values rule adc and temp 1,values end ANALOG A1 300 AND BME280 Temperature 28.0 In that case, the value and trigger arguments passed to the rule function are also lists: python def function name values:list of string, triggers:list of string, msg end msg remains unchanged. Teleperiod rules ~ teleperiod-rules Teleperiod rules are supported with a different syntax from Tasmota rules. Instead of using Tele- prefix, you must use Tele . For example Tele ANALOG Temperature1 instead of Tele-ANALOG Temperature1 Rules operators ~ rules-operators | Operator | Function | |---|---| String Operators | | = | equal to used for string comparison | == | not equal to used for string comparison | $< | string starts with | $ | string ends with | $\| | string contains | $ | string is not equal to | $^ | string do not contains | Numerical Operators | | == | equal to used for numerical comparison | | greater than | < | lesser than | = | number not equal to | = | greater than or equal to | <= | lesser than or equal to | \| | Modulo division to this number is 0 remainder=0 | Timers ~ timers Berry code, when it is running, blocks the rest of Tasmota. This means that you should not block for too long, or you may encounter problems. As a rule of thumb, try to never block more than 50ms. If you need to wait longer before the next action, use timers. As you will see, timers are very easy to create thanks to Berry's functional nature. All times are in milliseconds. You can know the current running time in milliseconds since the last boot: tasmota.millis 9977038 Sending a timer is as easy as tasmota.set timer