Skip to content

Commit

Permalink
Add Berry page
Browse files Browse the repository at this point in the history
  • Loading branch information
s-hadinger committed Feb 14, 2021
1 parent db0fdce commit b1f101f
Showing 1 changed file with 173 additions and 0 deletions.
173 changes: 173 additions & 0 deletions docs/Berry-Scripting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Berry Scripting Language
!!! failure "This feature is experimental, ESP32 only and currently not included in precompiled binaries"

To use it you must [compile your build](Compile-your-build). Add the following to `user_config_override.h`:

```arduino
#define USE_BERRY
```

## Introduction to Berry

Berry is a ultra-lightweight dynamically typed embedded scripting language. It is designed for lower-performance embedded devices.

https://github.com/Skiars/berry

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 syntax, support 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

This version is primarily targeted for ESP32. The RAM usage starts at ~10kb which makes it tight for ESP8266. However, for development purpose, the Berry module does compile on ESP8266, although it is not optimized nor supported (this might change in the future).

The Tasmota integration is far from complete and the following will be added later:

- file system support to save scripts and bytecode
- use of a native Tasmota module (it is currently emulated with a Class)
- LVGL integration
- (much more...)

## Examples

### Interactive mode

Initialization:

```
00:00:00.079 BRY: Berry initialized, RAM consumed=14160 (Heap=301040)
```

Use the command `Br` to use interactive mode commands:

```
12:50:56.830 CMD: br 1+1
12:50:56.837 RSL: stat/tasmota_B90B50/RESULT = {"Br":"2"}
12:51:07.880 CMD: br a=3
12:51:07.888 RSL: stat/tasmota_B90B50/RESULT = {"Br":"3"}
12:51:11.430 CMD: br a=a+1
12:51:11.438 RSL: stat/tasmota_B90B50/RESULT = {"Br":"4"}
12:51:15.180 CMD: br b
12:51:15.187 RSL: stat/tasmota_B90B50/RESULT = {"Br":"[syntax_error] input:1: 'b' undeclared (first use in this function)"}
12:51:22.880 CMD: br tasmota.getfreeheap()
12:51:22.887 RSL: stat/tasmota_B90B50/RESULT = {"Br":"230092"}
12:51:32.080 CMD: br log("Hello Tasmota!")
12:51:32.085 Hello Tasmota!
12:51:32.087 RSL: stat/tasmota_B90B50/RESULT = {"Br":"Hello Tasmota!"}
```

## Reference

Below are the Tasmota specific functions and modules implemented on top of Berry.

### Differences with native Berry

The Berry native `print()` function outputs to Hardware Serial and should not be used, except for very specific debug purposes.

#### `log(msg:string [, level:int = 3]) -> string`

Logs a message to the Tasmota console. Optional second argument is log_level (0..4), default is `2` `LOG_LEVEL_INFO`.

Example:

```
12:55:50.949 CMD: br log("a")
12:55:50.954 a
(log_level is 2)
12:56:05.699 CMD: br log("b",3)
12:56:05.706 RSL: stat/tasmota_B90B50/RESULT = {"Br":"3"}
```

### `module tasmota`


Tasmota specific functions are now in the `tasmota` module.
Tasmota automatically imports all modules; i.e. the following commands are done at startup:

```
import string
import json
import gc
import tasmota
import tasmota as t
```


#### `tasmota.getfreeheap() -> int`

Returns the number of free bytes on the Tasmota heap.

Example:

```
br tasmota.getfreeheap()
20:29:08.758 CMD: br tasmota.getfreeheap()
20:29:08.765 RSL: stat/tasmota_67B1E9/RESULT = {"Br":"25408"}
```

#### `tasmota.publish(topic:string, payload:string[, retain:bool]) -> nil`

Equivalent of `publish` command, publishes a MQTT message on `topic` with `payload`. Optional `retain` parameter.

Example:

```
br tasmota.publish('my_topic','message')
20:28:30.504 CMD: br tasmota.publish('my_topic','message')
20:28:30.510 RSL: my_topic = message
20:28:30.512 RSL: stat/tasmota_67B1E9/RESULT = {"Br":"message"}
```

#### `tasmota.cmd(command:string) -> string`

Sends any command to Tasmota, like it was type in the console. It returns the result of the command if any.

Example:

```
br tasmota.cmd("Dimmer 50")
20:32:19.227 CMD: br tasmota.cmd("Dimmer 50")
20:32:19.235 RSL: stat/tasmota_67B1E9/RESULT = {"POWER":"ON","Dimmer":50,"Color":"808080","HSBColor":"0,0,50","Channel":[50,50,50]}
20:32:19.238 BRY: Error be_top is non zero=1
20:32:19.242 RSL: stat/tasmota_67B1E9/RESULT = {"Br":"{"POWER":"ON","Dimmer":50,"Color":"808080","HSBColor":"0,0,50","Channel":[50,50,50]}"}
```

#### `tasmota.millis([delay:int]) -> int`

Returns the number of milliseconds since last reboot. The optional parameter lets you specify the number of milliseconds in the future; useful for timers.

Example:

```
br tasmota.millis()
20:33:52.671 CMD: br tasmota.millis()
20:33:52.677 RSL: stat/tasmota_67B1E9/RESULT = {"Br":"1207263"}
```

#### `tasmota.timereached(timer:int) -> bool`

Checks whether the timer (in milliseconds) has been reached or not. Always use this function and don't do compares between `millis()` and timers, because of potential sign and overflow issues.

Example:

```
br t = tasmota.millis(5000)
20:36:23.523 CMD: br t = tasmota.millis(5000)
20:36:23.532 RSL: stat/tasmota_67B1E9/RESULT = {"Br":"1363118"}
br tasmota.timereached(t)
20:36:36.806 CMD: br tasmota.timereached(t)
20:36:36.813 RSL: stat/tasmota_67B1E9/RESULT = {"Br":"true"}
```

0 comments on commit b1f101f

Please sign in to comment.