# Script

Script node allows users to run custom Python scripts on the device. Due to the computational resource constraints, script node
shouldn't be used for heavy computing (eg. image manipulation/CV), but for managing the flow of the pipeline (business logic).
Example use cases would be controlling nodes like
[ImageManip](https://docs.luxonis.com/software/depthai-components/nodes/image_manip.md),
[ColorCamera](https://docs.luxonis.com/software/depthai-components/nodes/color_camera.md),
[SpatialLocationCalculator](https://docs.luxonis.com/software/depthai/examples/spatial_location_calculator.md), decoding
[NeuralNetwork](https://docs.luxonis.com/software/depthai-components/nodes/neural_network.md) results, or interfacing with GPIOs.
For debugging scripts, we suggest
[script_logging](https://docs.luxonis.com/software/depthai/examples/script_change_pipeline_flow.md).

## How to place it

#### Python

```python
pipeline = dai.Pipeline()
script = pipeline.create(dai.node.Script)
```

#### C++

```cpp
dai::Pipeline pipeline;
auto script = pipeline.create<dai::node::Script>();
```

## Inputs and Outputs

Users can define as many inputs and outputs as they need. Inputs and outputs can be any
[components_messages](https://docs.luxonis.com/software/depthai-components/messages/message_group.md) type.

## Usage

#### Python

```python
script = pipeline.create(dai.node.Script)
script.setScript("""
    import time
    import marshal
    num = 123
    node.warn(f"Number {num}") # Print to host
    x = [1, "Hello", {"Foo": "Bar"}]
    x_serial = marshal.dumps(x)
    b = Buffer(len(x_serial))
    while True:
        time.sleep(1)
        b.setData(x_serial)
        node.io['out'].send(b)
""")
script.outputs['out'].link(xout.input)

# ...
# After initializing the device, enable log levels
device.setLogLevel(dai.LogLevel.WARN)
device.setLogOutputLevel(dai.LogLevel.WARN)
```

#### C++

```cpp
auto script = pipeline.create<dai::node::Script>();
script->setScript(R"(
    import time
    import marshal
    num = 123
    node.warn(f"Number {num}") # Print to host
    x = [1, "Hello", {"Foo": "Bar"}]
    x_serial = marshal.dumps(x)
    b = Buffer(len(x_serial))
    while True:
        time.sleep(1)
        b.setData(x_serial)
        node.io['out'].send(b)
)");
script->outputs["out"].link(xout->input);

// ...
// After initializing the device, enable log levels
device.setLogLevel(dai::LogLevel.WARN);
device.setLogOutputLevel(dai::LogLevel.WARN);
```

## Interfacing with GPIOs

In the script node you can interface with GPIOs of the VPU using module GPIO. Currently supported functions are:

```python
# Module
import GPIO

# General
GPIO.setup(gpio, dir, pud, exclusive)
GPIO.release(gpio)
GPIO.write(gpio, value)
GPIO.read(gpio)

# Interrupts
GPIO.waitInterruptEvent(gpio = -1) # blocks until any interrupt or interrupt by specified gpio is fired. Interrupts with callbacks are ignored here
GPIO.hasInterruptEvent(gpio = -1) # returns whether interrupt happened on any or specified gpio. Interrupts with callbacks are ignored here
GPIO.setInterrupt(gpio, edge, priority, callback = None) # adds interrupt to specified pin
GPIO.clearInterrupt(gpio) # clears interrupt of specified pin

# PWM
GPIO.setPwm(gpio, highCount, lowCount, repeat=0) # repeat == 0 means indefinite
GPIO.enablePwm(gpio, enable)

# Enumerations
GPIO.Direction: GPIO.IN, GPIO.OUT
GPIO.State: GPIO.LOW, GPIO.HIGH
GPIO.PullDownUp: GPIO.PULL_NONE, GPIO.PULL_DOWN, GPIO.PULL_UP
GPIO.Edge: GPIO.RISING, GPIO.FALLING, GPIO.LEVEL_HIGH, GPIO.LEVEL_LOW
```

Here's an example of toggling GPIO pin 40 inside Script node from the host (via
[XLinkIn](https://docs.luxonis.com/software/depthai-components/nodes/xlink_in.md)). On
[OAK-SoM-Pro](https://shop.luxonis.com/products/oak-som-pro), GPIO 40 drives FSYNC signal for both 4-lane cameras, and we have
used the code below for this exact reason.

```python
import GPIO
MX_PIN = 40

ret = GPIO.setup(MX_PIN, GPIO.OUT, GPIO.PULL_DOWN)
toggleVal = True

while True:
  data = node.io['in'].get()  # Wait for a message from the host computer

  node.warn('GPIO toggle: ' + str(toggleVal))
  toggleVal = not toggleVal
  ret = GPIO.write(MX_PIN, toggleVal)  # Toggle the GPIO
```

## Time synchronization

Script node has access to both device (internal) clock and also synchronized host clock. Host clock is synchronized with device
clock at below 2.5ms precision at 1σ, [Host clock syncing](https://docs.luxonis.com/software/depthai-components/device.md).

```python
import time
interval = 60
ctrl = CameraControl()
ctrl.setCaptureStill(True)
previous = 0
while True:
    time.sleep(0.001)

    tnow_full = Clock.nowHost() # Synced clock with host
    # Clock.now() -> internal/device clock
    # Clock.offsetToHost() -> Offset between internal/device clock and host clock

    now = tnow_full.seconds
    if now % interval == 0 and now != previous:
        previous = now
        node.warn(f'{tnow_full}')
        node.io['out'].send(ctrl)
```

## Using DepthAI [Messages](https://docs.luxonis.com/software/depthai-components/messages.md)

The depthai module is implicitly imported to the script node. You can create new depthai messages and assign data to it, for
example:

```python
buf = Buffer(100) # Assign 100 bytes to the Buffer message

# Create CameraControl message, set manual focus
control = CameraControl()
control.setManualFocus(100)

imgFrame = ImgFrame(300*300*3) # Buffer with 300x300x3 bytes
```

## Available modules and libraries

Available modules

```text
"posix", "errno", "pwd", "_sre", "_codecs", "_weakref", "_functools", "_operator",
"_collections", "_abc", "itertools", "atexit", "_stat", "time", "_datetime", "math",
"_thread", "_io", "_symtable", "marshal", "_ast", "gc", "_warnings", "_string", "_struct"
```

Available Modules for LEON_CSS:

```text
"binascii", "_random", "_socket", "_md5", "_sha1", "_sha256", "_sha512", "select",
"array", "unicodedata"
```

Libraries

```text
"__main__", "_collections_abc", "_frozen_importlib", "_frozen_importlib_external",
"_sitebuiltins", "abc", "codecs", "datetime", "encodings", "encodings.aliases",
"encodings.ascii", "encodings.latin_1", "encodings.mbcs", "encodings.utf_8", "genericpath",
"io", "os", "posixpath", "site", "stat", "threading", "types", "struct", "copyreg",
"reprlib", "operator", "keyword", "heapq", "collections", "functools", "sre_constants",
"sre_parse", "sre_compile", "enum", "re", "json", "json.decoder", "json.encoder",
"json.scanner", "textwrap"
```

Libraries for LEON_CSS:

```text
"http", "http.client", "http.server", "html", "mimetypes", "copy", "shutil", "fnmatch",
"socketserver", "contextlib", "email", "email._encoded_words", "email._header_value_parser",
"email._parseaddr", "email._policybase", "email.base64mime", "email.charset",
"email.contentmanager",  "email.encoders", "email.errors", "email.feedparser",
"email.generator", "email.header", "email.headerregistry", "email.iterators", "email.message",
"email.parser", "email.policy", "email.quoprimime", "email.utils", "string", "base64",
"quopri", "random", "warnings", "bisect", "hashlib", "logging", "traceback", "linecache",
"socket", "token", "tokenize", "weakref", "_weakrefset", "collections.abc", "selectors",
"urllib", "urllib.parse", "calendar", "locale", "uu", "encodings.idna", "stringprep"
```

The difference between module and library is that module is a precompiled C source with Python bindings, whereas library is Python
source code packed into a library and precompiled into Python bytecode (before loaded into our Firmware).

Networking/protocol modules/libraries that are available on the LEON_CSS can only be used on [OAK POE
device](https://docs.luxonis.com/hardware.md#poe-designs). You can specify on which processor the script will run, eg. for
LEON_CSS:

```python
script = pipeline.create(dai.node.Script)
script.setProcessor(dai.ProcessorType.LEON_CSS)
```

## Examples of functionality

 * [Script camera control](https://docs.luxonis.com/software/depthai/examples/script_camera_control.md) - Controlling the camera
 * [Script get local IP](https://docs.luxonis.com/software/depthai/examples/script_get_ip.md) - Get local IP
 * [Script HTTP client](https://docs.luxonis.com/software/depthai/examples/script_http_client.md) - Send HTTP request
 * [Script TCP streaming](https://github.com/luxonis/oak-examples/tree/master/gen2-poe-tcp-streaming) - TCP communication from
   within Script node, either in host or client mode
 * [Script MQTT publishing](https://github.com/luxonis/oak-examples/tree/master/gen2-poe-mqtt) - MQTT publishing from within
   Script node
 * [Script HTTP server](https://docs.luxonis.com/software/depthai/examples/script_http_server.md) - still image over HTTP
 * [Script MJPEG server](https://docs.luxonis.com/software/depthai/examples/script_mjpeg_server.md) - MJPEG video stream over HTTP
 * [Script NNData example](https://docs.luxonis.com/software/depthai/examples/script_nndata_example.md) - Constructs
   [NNData](https://docs.luxonis.com/software/depthai-components/messages/nn_data.md)
 * [Triangulation experiment](https://github.com/luxonis/oak-examples/blob/master/gen2-triangulation/main.py)
 * [Movenet decoding (edge mode)](https://github.com/geaxgx/depthai_movenet/blob/main/template_processing_script.py) - A bit more
   complex example by geaxgx

## Reference

### depthai.node.Script(depthai.Node)

Kind: Class

#### getProcessor(self) -> depthai.ProcessorType: depthai.ProcessorType

Kind: Method

Get on which processor the script should run

Returns:
Processor type - Leon CSS or Leon MSS

#### getScriptName(self) -> str: str

Kind: Method

Get the script name in utf-8.

When name set with setScript() or setScriptPath(), returns that name. When
script loaded with setScriptPath() with name not provided, returns the utf-8
string of that path. Otherwise, returns "<script>"

Returns:
std::string of script name in utf-8

#### setProcessor(self, arg0: depthai.ProcessorType)

Kind: Method

Set on which processor the script should run

Parameter ``type``:
Processor type - Leon CSS or Leon MSS

#### setScript()

Kind: Method

#### setScriptPath()

Kind: Method

#### inputs

Kind: Property

#### outputs

Kind: Property

### Need assistance?

Head over to [Discussion Forum](https://discuss.luxonis.com/) for technical support or any other questions you might have.
