Configuring Heedy

If you are an admin of your heedy instance, you can perform all server maintenance and apply configuration changes directly from the “Settings” UI. Heedy will automatically perform a full database backup when restarting on each configuration change made from the web UI, so if the server fails to restart for any reason, any changes you made will be automatically reverted.

Installing Plugins

You can install a plugin using the web UI by uploading a zip file containing the plugin folder. Plugin Upload UI

You will be prompted to restart heedy to activate the plugin. It is highly recommended that you check the box for a database backup whenever installing new plugins which might modify your database. That way, if there are issues, heedy can revert the entire update, including any changes to the database.

Manually Installing Plugins

You can also manually upload a plugin by extracting the zip file, and placing the plugin folder in the plugins subdirectory of your database folder.

That is, suppose your heedy database folder is at ./myheedy. Then installing the plugin myplugin can be achieved as follows using bash:

unzip myplugin-1.0.0.zip
mkdir ./myheedy/plugins
mv myplugin ./myheedy/plugins/

You will then need to enable the plugin by modifying your heedy.conf vim ./myheedy/heedy.conf to add myplugin to the active plugins array:

active_plugins = ["fitbit","notebook","myplugin"]

You will need to restart heedy for the changes to take effect.

Default Configuration

Your heedy.conf is simply overriding the configuration options defined in the plugins you installed, as well as the core built-in settings. You can modify most of these options by setting their values in your heedy.conf.

The built-in configuration, shown here, contains a lot of heedy’s internals, including the configurations for the plugins that are built into heedy by default. For this reason, unless you know what you are doing, it is recommended that you leave most options at their default values.

/*
    This file represents the default configuration for a heedy server.

    You can override any of these options in your server's heedy.conf,
    or in your plugin's configuration file.

*/

// By default, listen on all interfaces. 
host=""
// The port on which to run heedy
port = 1324
// The URL used for callbacks
url=""

// The list of users who are given administrative permissions. 
// The user created when setting up heedy is automatically added here
admin_users = []

// These are the builtin plugins that are active by default.
active_plugins = ["notifications","dashboard","timeseries","registry","python","kv"]

// Forbid the following usernames from being created
forbidden_users = ["admin","heedy","public","users"]

// The SQL app string to use to connect to the database, in the form:
//  <sql type>://<app string>
// By default, heedy uses an sqlite3 database saved in the data subfolder
sql = "sqlite3://heedy.db?_journal=WAL"

// frontend gives the javascript module which implements the main UI
frontend = "heedy/main.mjs"
// preload is a list of modules which will be required for the frontend to load
preload = ["main.mjs","dist/vue.mjs","dist/moment.mjs","rest.mjs","worker.mjs",
    "dist/codemirror.mjs","dist/draggable.mjs","dist/markdown-it.mjs",
    "dist/vuetify-jsonschema-form.mjs"]

// The number of bytes to allow in a REST request body. 
// NOTE: This does not apply to datapoint inserts in timeseries, 
// which are allowed to be of arbitrary size 
// TODO: currently it DOES apply to datapoint inserts.
request_body_byte_limit = 4e+6

// Whether or not to permit the public to connect to websockets.
// Note that even if true, they will only have public-level access to events.
// This allows public not to take websocket resources from users
allow_public_websocket = false

// The timeout between asking a plugin nicely to shut down and killing it.
run_timeout = "10s"

// Runtypes that come compiled into heedy's core. The builtin runtype refers to
// built-in code that is run on the given key. The exec runtype allows plugins
// to run arbitrary executables as follows:
//      plugin "myplugin" {
//          run "myexecutable" {
//              type="exec"
//              cmd=["./myexecutable","--arg1"]
//          }
//      }
runtype "builtin" {
    schema = {
        "key": {"type": "string"},
        "required": ["key"]
    }
}
runtype "exec" {
    schema = {
        "cmd": {"type": "array", "items": {"type": "string"}, "minItems": 1},
        "api": {"type": "string"},
        "required": ["cmd"]
    }
}

// -----------------------------------------------------------------------------
// NOTIFICATIONS
// 

plugin "notifications" {
    version= version
    description= "Allow plugins and apps to notify a user of their status"
    frontend= "notifications/main.mjs"

    run "server" {
        type = "builtin"
        key = "notifications"
    }

    routes = {
        "/api/notifications": "run://server"
    }
}


// -----------------------------------------------------------------------------
// DASHBOARD
// 

plugin "dashboard" {
    version= version
    description= join("Dashboards are a builtin object that handles",
                        " display and visualization of info from various sources")
    frontend= "dashboard/main.mjs"

    run "server" {
        type = "builtin"
        key = "dashboard"
    }

    settings_schema = {
        "types": {
            "type": "object",
            "description": "The definitions of all dashboard types",
            "default": {},
            "additionalProperties": { 
                "type": "object", 
                "properties": {
                    "api": {
                        "type":"string"
                    },
                    "query_schema": {
                        "type":"object",
                        "default": {}
                    },
                    "frontend_schema": {
                        "type":"object",
                        "default": {}
                    }
                },
                "required": ["api"]
            
            }
        }
    }

    types = {
        "dataset": {
            "api": "run://timeseries:server/dashboard"
        }
    }

}

// The dashboard object is built in - its implementation comes as part of the 
// dashboard plugin. Note that the builtin dashboard object cannot be disabled, 
// even if the plugin itself is inactive. This is because an object type 
// is globally defined in the configuration.
type "dashboard" {

    // meta gives the schema required for dashboard metadata 
    // (in the "meta" field of the dashboard object)
    meta = {}

    routes = {
        "/dashboard": "run://dashboard:server/object"
        "/dashboard/*": "run://dashboard:server/object"
    }
}

// -----------------------------------------------------------------------------
// TIMESERIES
// 

plugin "timeseries" {
    version= version
    description= join("Timeseries are a builtin object that handles",
                        " time-series data and visualization")
    frontend= "timeseries/main.mjs"
    preload=["timeseries/worker.mjs"]

    run "server" {
        type = "builtin"
        key = "timeseries"
    }

    routes = {
        "POST /api/dataset": "run://server"
    }

}

// The timeseries object is built in - its implementation comes as part of the 
// timeseries plugin. Note that the builtin timeseries object cannot be disabled, 
// even if the plugin itself is inactive. This is because an object type 
// is globally defined in the configuration.
type "timeseries" {

    // meta gives the schema required for timeseries metadata 
    // (in the "meta" field of the timeseries object)
    meta = {
        "schema": {
            "type": "object",
            "default": {}
        },
        "actor": {
            "type": "boolean",
            "default": false
        },
        "subtype": {
            "type": "string"
        },
        "required": ["schema","actor"]
    }

    routes = {
        "/timeseries": "run://timeseries:server/object"
        "/timeseries/*": "run://timeseries:server/object"
        "/actions": "run://timeseries:server/object"
        "/actions/*": "run://timeseries:server/object"
        "/act": "run://timeseries:server/object"
    }

    // These are the scope defined specifically for timeseries
    scope = {
        "act": "Allows intervention"
    }

}

// -----------------------------------------------------------------------------
// KV
// 

plugin "kv" {
    version = version
    description = "Key-value storage for apps and plugins"

    run "server" {
        type = "builtin"
        key = "kv"
    }

    routes = {
        "/api/kv/*": "run://server"
    }
}

// -----------------------------------------------------------------------------
// PYTHON
// 

plugin "python" {
    version= version
    description= "Support for running python-based plugins"

    run "server" {
        type = "builtin"
        key = "python"
    }

    settings_schema = {
        "path": {
            "type": "string",
            "description": "Path to the python interpreter to use",
            "default": ""
        },
        "pip_args": {
            "type":"array",
            "items": {"type": "string"},
            "description": join(
                    "Command-line arguments to pass to pip (pip install {args}",
                    " mypackage or pip install {args} -r requirements.txt)"),
            "default": []
        }
    }
}

// The python runtype allows running a python file using the Python interpreter
// configured in heedy. Furthermore, it also makes sure any dependecies
// in a requirements.txt are installed before running the file.
runtype "python" {
    schema = {
        "path": {
            "type": "string"
        },
        "args": {
            "type": "array",
            "items": {"type": "string"},
            "default": []
        },
        "api": {"type": "string"},
        "required": ["path"]
    }
    api = "run://python:server/runtypes/python"
}

// -----------------------------------------------------------------------------
// REGISTRY
// 

plugin "registry" {
    version = version
    description = "Add/remove plugins, update and install new ones."

    frontend = "registry/main.mjs"
}