mqtt-scripts is a Node.js based script runner for use in mqtt based smart home environments.
It's intentended to be used as the "logic layer" in your smart home, and offers a zero-boilerplate, straight forward scripting environment.
It follows the mqtt-smarthome architecture. Mqtt-scripts could be seen as something like "Node-RED without GUI"
Prerequisites: mqtt-scripts needs Node.js >= 6.0.
- Install mqtt-scripts globally:
sudo npm install -g mqtt-scripts
- Create a folder from where mqtt-scripts will load the scripts:
mkdir -p /opt/mqtt-smarthome/scripts
- Create a folder to install node modules that can be used in the scripts:
mkdir /opt/mqtt-smarthome/scripts/node_modules
(You can then just use npm install in the directory /opt/mqtt-smarthome/scripts)
- Put some files in you script dir:
echo "log.info('my first script!')" > /opt/mqtt-smarthome/scripts/test1.js
echo "log.info 'get ma a coffee' > /opt/mqtt-smarthome/scripts/test1.coffee
- Start mqtt-scripts
mqtt-scripts -d /opt/mqtt-smarthome/scripts
To run with Docker, use either a pre-build image or build one your own. Either way, just substitude the node-command you would have used by the Docker command, for e.g.:
mqtt-scripts --help
becomes
docker run dersimn/mqtt-scripts:1 --help
An example for a productive configuration would be:
docker run -d --restart=always --name=logic \
    -e "TZ=Europe/Berlin" \
    -v /opt/hma/etc/scripts:/scripts:ro \
    dersimn/mqtt-scripts:1 \
    --url mqtt://10.1.1.50 \
    --dir /scripts
Configure via MQTTSCRIPTS_ env variables when using Docker Compose.
Docker development build:
docker build -t mqtt-scripts .
docker run --rm mqtt-scripts --help
Docker Hub deploy:
docker buildx create --name mybuilder
docker buildx use mybuilder
docker buildx build --platform linux/amd64,linux/arm/v7 -t dersimn/mqtt-scripts:1 -t dersimn/mqtt-scripts:1.x.x --push .
Usage: mqtt-scripts [options]
Options:
  --version                Show version number                         [boolean]
  -c, --config             Path to JSON config file
  -d, --dir                directory to scan for .js and .coffee files. can be
                           used multiple times.
  -h, --help               Show help                                   [boolean]
  -s, --variable-prefix    topic prefix for $ substitution (shorthand for
                           variables, see docs)                 [default: "var"]
  -t, --disable-variables  disable variable feedback (see docs) [default: false]
  -n, --name               instance name. used as mqtt client id and as prefix
                           for connected topic                [default: "logic"]
  -u, --url                mqtt broker url. See
                           https://github.com/mqttjs/MQTT.js#connect-using-a-url
                                                   [default: "mqtt://127.0.0.1"]
  -v, --verbosity          possible values: "error", "warn", "info", "debug"
                                                               [default: "info"]
  -w, --disable-watch      disable file watching (don't exit process on file
                           changes)                             [default: false]
  -l, --latitude                                              [default: 48.7408]
  -m, --longitude                                              [default: 9.1778]                                            
If you're running multiple instances of mqtt-scripts you have to decide which one should handle variables and disable the variables on all other instances with the --disable-variable option.
link('hm//RC4:1/PRESS_CONT', 'hue//lights/Hobbyraum/bri_inc', -16);
subscribe('hm//RC4:2/PRESS_CONT', function () {
    if (!getValue('hue//lights/Hobbyraum')) {
        setValue('hue//lights/Hobbyraum', 1);
    } else {
        setValue('hue//lights/Hobbyraum/bri_inc', 16);
    }
});
link('hm//RC4:1/PRESS_SHORT', 'hue//lights/Hobbyraum', 0);
link('hm//RC4:2/PRESS_SHORT', 'hue//lights/Hobbyraum', 254);
link('hm//RC4:3/PRESS_CONT', 'hue//lights/Hobbyraum/ct_inc', -16);
link('hm//RC4:4/PRESS_CONT', 'hue//lights/Hobbyraum/ct_inc', 16);
link('hm//RC4:3/PRESS_SHORT', 'hue//lights/Hobbyraum/ct', 153);
link('hm//RC4:4/PRESS_SHORT', 'hue//lights/Hobbyraum/ct', 500);var request =   require('request');
var cred =      require('./lib/credentials.js');
var url = 'https://creativecommons.tankerkoenig.de/json/detail.php';
var tankstellen = {
    'OMV': 'cb1f0588-d517-40f0-8ce3-3edadebea40d',
    'Shell': '4267c196-eea1-47be-96b7-d790b2fbd17a'
};
schedule('0/12 * * * *', function () {
    for (var topic in tankstellen) {
        getData(topic, tankstellen[topic]);
    }
});
function getData(topic, id) {
    request.get(url + '?id=' + id + '&apikey=' + cred.tankerkoenig.apikey, function (err, res) {
        if (err) {
            log.error(err);
            return;
        }
        var data = JSON.parse(res.body).station;
        setValue('$Tankstelle/' + topic + '/Diesel',    data.diesel);
        setValue('$Tankstelle/' + topic + '/E5',        data.e5);
        setValue('$Tankstelle/' + topic + '/Offen',     data.isOpen);
    });
}var cred = require('./lib/credentials.js');
var pushoverNotifications = require('pushover-notifications');
var push = new pushoverNotifications( {
    user: cred.pushover.user,
    token: cred.pushover.token,
    onerror: function (error) {
        log.error(error);
    }
});
function pushover(msg) {
    if (typeof msg !== 'object' || typeof msg.message !== 'string') msg = {message: '' + msg};
    msg.title = msg.title || "Smart Home";
    msg.priority = msg.priority || 0;
    msg.device = msg.device || 'iphone5';
    push.send(msg, function(err, result) {
        if (err) {
            log.error(err);
        }
    });
}
subscribe('$Anwesenheit', {change: true}, function () {
    pushover({
        title:'Anwesenheit',
        message: getProp($Anwesenheit, 'logic_textual'),
        priority: -1
    });
});- log
- Log to stdout/stderr. Messages are prefixed with a timestamp and the calling scripts path. 
- subscribe(topic, [options], callback)
- Subscribe to MQTT topic(s) 
- schedule(pattern, [options], callback)
- Schedule recurring and one-shot events 
- sunSchedule(pattern, [options], callback)
- Schedule a recurring event based on sun position 
- publish(topic, payload, [options])
- Publish a MQTT message 
- setValue(topic, val)
- Set a value on one or more topics 
- getValue(topic) ⇒ mixed
- getProp(topic, [...property]) ⇒ mixed
- Get a specific property of a topic 
- now() ⇒ number
- age(topic) ⇒ number
- link(source, target, [value])
- Link topic(s) to other topic(s) 
- combineBool(srcs, targets)
- Combine topics through boolean or 
- combineMax(srcs, targets)
- Publish maximum of combined topics 
- timer(src, target, time)
- Publishes 1 on target for specific time after src changed to true 
- subscribeCallback : function
Log to stdout/stderr. Messages are prefixed with a timestamp and the calling scripts path.
Kind: global class
Log a debug message
Kind: static method of log
| Type | 
|---|
| * | 
Log an info message
Kind: static method of log
| Type | 
|---|
| * | 
Log a warning message
Kind: static method of log
| Type | 
|---|
| * | 
Log an error message
Kind: static method of log
| Type | 
|---|
| * | 
Subscribe to MQTT topic(s)
Kind: global function
| Param | Type | Description | 
|---|---|---|
| topic | string|Array.<string> | topic or array of topics to subscribe | 
| [options] | Object|string|function | Options object or as shorthand to options.condition a function or string | 
| [options.shift] | number | delay execution in seconds. Has to be positive | 
| [options.random] | number | random delay execution in seconds. Has to be positive | 
| [options.change] | boolean | if set to true callback is only called if val changed | 
| [options.retain] | boolean | if set to true callback is also called on retained messages | 
| [options.condition] | string|function | conditional function or condition string | 
| callback | subscribeCallback | 
Schedule recurring and one-shot events
Kind: global function
See: sunSchedule for scheduling based on sun position.
| Param | Type | Description | 
|---|---|---|
| pattern | string|Date|Object|Array.<mixed> | pattern or array of patterns. May be cron style string, Date object or node-schedule object literal. See https://github.com/tejasmanohar/node-schedule/wiki | 
| [options] | Object | |
| [options.random] | number | random delay execution in seconds. Has to be positive | 
| callback | function | is called with no arguments | 
Example
// every full Hour.
schedule('0 * * * *', callback);
// Monday till friday, random between 7:30am an 8:00am
schedule('30 7 * * 1-5', {random: 30 * 60}, callback);
// once on 21. December 2018 at 5:30am
schedule(new Date(2018, 12, 21, 5, 30, 0), callback);
// every Sunday at 2:30pm
schedule({hour: 14, minute: 30, dayOfWeek: 0}, callback);Schedule a recurring event based on sun position
Kind: global function
See: schedule for time based scheduling.
| Param | Type | Description | 
|---|---|---|
| pattern | string|Array.<string> | a suncalc event or an array of suncalc events. See https://github.com/mourner/suncalc | 
| [options] | Object | |
| [options.shift] | number | delay execution in seconds. Allowed Range: -86400...86400 (+/- 24h) | 
| [options.random] | number | random delay execution in seconds. | 
| callback | function | is called with no arguments | 
Example
// Call callback 15 minutes before sunrise
sunSchedule('sunrise', {shift: -900}, callback);
// Call callback random 0-15 minutes after sunset
sunSchedule('sunset', {random: 900}, callback);Publish a MQTT message
Kind: global function
| Param | Type | Default | Description | 
|---|---|---|---|
| topic | string|Array.<string> | topic or array of topics to publish to | |
| payload | string|Object | the payload string. If an object is given it will be JSON.stringified | |
| [options] | Object | the options to publish with | |
| [options.qos] | number | 0 | QoS Level | 
| [options.retain] | boolean | false | retain flag | 
Set a value on one or more topics
Kind: global function
| Param | Type | Description | 
|---|---|---|
| topic | string|Array.<string> | topic or array of topics to set value on | 
| val | mixed | 
Kind: global function
Returns: mixed - the topics value
| Param | Type | 
|---|---|
| topic | string | 
Get a specific property of a topic
Kind: global function
Returns: mixed - the topics properties value
| Param | Type | Description | 
|---|---|---|
| topic | string | |
| [...property] | string | the property to retrieve. May be repeated for nested properties. If omitted the whole topic object is returned. | 
Example
// returns the timestamp of a given topic
getProp('hm//Bewegungsmelder Keller/MOTION', 'ts');Kind: global function
Returns: number - ms since epoch
Kind: global function
Returns: number - seconds since last change
| Param | Type | 
|---|---|
| topic | string | 
Link topic(s) to other topic(s)
Kind: global function
| Param | Type | Description | 
|---|---|---|
| source | string|Array.<string> | topic or array of topics to subscribe | 
| target | string|Array.<string> | topic or array of topics to publish | 
| [value] | mixed | value to publish. If omitted the sources value is published. A function can be used to transform the value. | 
Combine topics through boolean or
Kind: global function
| Param | Type | Description | 
|---|---|---|
| srcs | Array.<string> | array of topics to subscribe | 
| targets | string | topic to publish | 
Publish maximum of combined topics
Kind: global function
| Param | Type | Description | 
|---|---|---|
| srcs | Array.<string> | array of topics to subscribe | 
| targets | string | topic to publish | 
Publishes 1 on target for specific time after src changed to true
Kind: global function
| Param | Type | Description | 
|---|---|---|
| src | string|Array.<string> | topic or array of topics to subscribe | 
| target | string | topic to publish | 
| time | number | timeout in milliseconds | 
Kind: global typedef
| Param | Type | Description | 
|---|---|---|
| topic | string | the topic that triggered this callback. +/status/# will be replaced by +//# | 
| val | mixed | the val property of the new state | 
| obj | object | new state - the whole state object (e.g. {"val": true, "ts": 12346345, "lc": 12346345} ) | 
| objPrev | object | previous state - the whole state object | 
| msg | object | the mqtt message as received from MQTT.js | 
MIT © Sebastian Raff