### Manage Scripts via MQTT-RPC in Bash Source: https://context7.com/wirenboard/wb-rules/llms.txt Exposes an RPC interface over MQTT for managing scripts (list, load, save, remove, rename, enable/disable) when the engine is started with the `-editdir` flag. Requires `mosquitto_pub` for interaction. ```bash # List all script files mosquitto_pub -t '/rpc/v1/wbrules/Editor/List/myclient' \ -m '{"id": 1, "params": {}}' # Response on /rpc/v1/wbrules/Editor/List/myclient/reply: # {"id":1,"result":[{"virtualPath":"rules.js","enabled":true,"rules":[...],"devices":[...]}]} # Load script content mosquitto_pub -t '/rpc/v1/wbrules/Editor/Load/myclient' \ -m '{"id": 2, "params": {"path": "rules.js"}}' # Response: {"id":2,"result":{"content":"defineRule(...","enabled":true}} # Save script (creates or updates) mosquitto_pub -t '/rpc/v1/wbrules/Editor/Save/myclient' \ -m '{"id": 3, "params": {"path": "newrule.js", "content": "defineRule(\"test\", {whenChanged: \"dev/ctrl\", then: function() { log(\"test\"); }});"}}' # Response: {"id":3,"result":{"path":"newrule.js"}} # On syntax error: {"id":3,"result":{"error":"SyntaxError: ...","traceback":[{"line":1,"name":"newrule.js"}]}} # Enable/disable script mosquitto_pub -t '/rpc/v1/wbrules/Editor/ChangeState/myclient' \ -m '{"id": 4, "params": {"path": "rules.js", "state": false}}' # Response: {"id":4,"result":true} # Rename script mosquitto_pub -t '/rpc/v1/wbrules/Editor/Rename/myclient' \ -m '{"id": 5, "params": {"path": "old.js", "new_path": "new.js"}}' # Response: {"id":5,"result":true} # Remove script mosquitto_pub -t '/rpc/v1/wbrules/Editor/Remove/myclient' \ -m '{"id": 6, "params": {"path": "unwanted.js"}}' # Response: {"id":6,"result":true} ``` -------------------------------- ### Send Notifications using the `Notify` Object in JavaScript Source: https://context7.com/wirenboard/wb-rules/llms.txt The `Notify` object provides methods for sending emails, SMS messages (via ModemManager or Gammu, with custom command support), and Telegram messages. This is vital for alerting users or administrators about system events or critical conditions. The example demonstrates sending various notification types and a practical rule for critical alerts. ```javascript Notify.sendEmail( "admin@example.com", "Alert: Temperature High", "Current temperature: " + dev["wb-w1/28-00000a000001"] + "°C\nThreshold exceeded!" ); Notify.sendSMS("+71234567890", "Alert: System temperature critical!"); Notify.sendSMS( "+71234567890", "Custom gateway message", "/path/to/sender.py --number {} --text \"{}\"" ); Notify.sendTelegramMessage( "1234567890:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "123456789", "System alert: Temperature exceeded threshold!" ); defineRule("critical_alert", { asSoonAs: function() { return dev["wb-w1/28-00000a000001"] > 50; }, then: function() { var temp = dev["wb-w1/28-00000a000001"]; var message = "CRITICAL: Temperature is " + temp + "°C"; Notify.sendEmail("admin@example.com", "Critical Temperature Alert", message); Notify.sendSMS("+71234567890", message); Notify.sendTelegramMessage("BOT_TOKEN", "CHAT_ID", message); log.error(message); } }); ``` -------------------------------- ### Create Virtual Devices with defineVirtualDevice Source: https://context7.com/wirenboard/wb-rules/llms.txt Creates virtual devices with custom controls that integrate with the MQTT topic tree and web interface. Supports various control types like switches, ranges, and pushbuttons. Returns a device object for managing controls. ```javascript // Create a thermostat virtual device var thermostat = defineVirtualDevice("room-thermostat", { title: { en: "Room Thermostat", ru: "Комнатный термостат" }, cells: { enabled: { title: { en: "Enabled", ru: "Включен" }, type: "switch", value: false }, setpoint: { title: "Target Temperature", type: "range", value: 22, min: 15, max: 30, units: "°C" }, current_temp: { title: "Current Temperature", type: "value", value: 0, readonly: true, precision: 1, units: "°C" }, mode: { title: "Mode", type: "value", value: 1, enum: { 1: { en: "Heat", ru: "Нагрев" }, 2: { en: "Cool", ru: "Охлаждение" }, 3: { en: "Auto", ru: "Авто" } } }, status: { title: "Status", type: "text", value: "Idle", readonly: true }, reset: { title: "Reset", type: "pushbutton" } } }); // Access virtual device controls dev["room-thermostat/enabled"] = true; dev["room-thermostat/setpoint"] = 24; log("Current setpoint: {}", dev["room-thermostat/setpoint"]); // Using the device object methods var deviceObj = getDevice("room-thermostat"); deviceObj.addControl("humidity", { type: "value", value: 50, units: "%", readonly: true }); var ctrl = deviceObj.getControl("setpoint"); ctrl.setTitle({ en: "Target Temp", ru: "Целевая темп." }); ctrl.setMin(10); ctrl.setMax(35); log("Control value: {}", ctrl.getValue()); // Check if control exists before operations if (deviceObj.isControlExists("humidity")) { deviceObj.removeControl("humidity"); } // Iterate through all controls deviceObj.controlsList().forEach(function(control) { log("Control: {} = {}", control.getId(), control.getValue()); }); ``` -------------------------------- ### Execute External Commands with runShellCommand and spawn Source: https://context7.com/wirenboard/wb-rules/llms.txt Allows execution of shell commands or spawning processes asynchronously. Supports output capture, input passing, and exit callbacks. Useful for interacting with the operating system or external tools. ```javascript // Simple shell command runShellCommand("echo 'Hello World'"); // Shell command with output capture runShellCommand("cat /etc/hostname", { captureOutput: true, exitCallback: function(exitCode, capturedOutput) { if (exitCode === 0) { log("Hostname: {}", capturedOutput.trim()); } else { log.error("Command failed with code {}", exitCode); } } }); // Shell command with error capture runShellCommand("ls /nonexistent", { captureOutput: true, captureErrorOutput: true, exitCallback: function(exitCode, stdout, stderr) { if (exitCode !== 0) { log.error("Error: {}", stderr); } } }); // Shell command with input runShellCommand("/usr/bin/python3 -c 'import sys; print(sys.stdin.read().upper())'", { captureOutput: true, input: "hello world", exitCallback: function(exitCode, output) { log("Result: {}", output); // "HELLO WORLD" } }); // Spawn process directly (not through shell) spawn("/usr/bin/curl", ["-s", "http://api.example.com/status"], { captureOutput: true, exitCallback: function(exitCode, output) { if (exitCode === 0) { var response = JSON.parse(output); log("API status: {}", response.status); } } }); // Practical example: control external hardware defineRule("activate_siren", { asSoonAs: function() { return dev["alarm-panel/triggered"]; }, then: function() { runShellCommand("gpio write 7 1"); // Activate GPIO pin setTimeout(function() { runShellCommand("gpio write 7 0"); // Deactivate after 30 seconds }, 30000); } }); ``` -------------------------------- ### Run wb-rules Engine from Command Line in Bash Source: https://context7.com/wirenboard/wb-rules/llms.txt Configures and runs the wb-rules engine using command-line arguments. Scripts are loaded from specified directories and automatically reloaded on modification. Debugging can be enabled. ```bash # Basic usage wb-rules /etc/wb-rules/ # With multiple script paths wb-rules /etc/wb-rules/ /usr/share/wb-rules-system/ # Enable debugging wb-rules -debug /etc/wb-rules/ ``` -------------------------------- ### Timers: setTimeout, setInterval, startTimer, startTicker in JavaScript Source: https://context7.com/wirenboard/wb-rules/llms.txt This section covers timer functionalities for delayed and periodic execution. `setTimeout` and `setInterval` provide standard JavaScript callback-based timers, while `startTimer` and `startTicker` offer named timers that integrate with the rule system. These are essential for scheduling actions and creating recurring tasks. ```javascript var timeoutId = setTimeout(function() { log("Delayed action executed"); dev["wb-gpio/A1_OUT"] = false; }, 5000); clearTimeout(timeoutId); var counter = 0; var intervalId = setInterval(function() { counter++; log("Tick #{}", counter); if (counter >= 10) { clearInterval(intervalId); log("Timer stopped after 10 ticks"); } }, 1000); startTimer("delayed_off", 30000); defineRule("handle_delayed_off", { when: function() { return timers.delayed_off.firing; }, then: function() { dev["wb-gpio/A1_OUT"] = false; log("Delayed off timer fired"); } }); startTicker("heartbeat", 5000); defineRule("heartbeat_handler", { when: function() { return timers.heartbeat.firing; }, then: function() { dev["mydevice/last_seen"] = Date.now(); } }); defineRule("stop_heartbeat", { asSoonAs: function() { return dev["mydevice/enabled"] === false; }, then: function() { timers.heartbeat.stop(); log("Heartbeat timer stopped"); } }); ``` -------------------------------- ### Subscribe to MQTT Topics with trackMqtt Source: https://context7.com/wirenboard/wb-rules/llms.txt Enables subscription to MQTT topics, including wildcard support (`+` and `#`). Executes a callback function when messages are received on subscribed topics. Ideal for monitoring device status and receiving events. ```javascript // Track specific topic trackMqtt("/devices/wb-adc/controls/Vin", function(message) { log("Vin value: {} (topic: {})", message.value, message.topic); }); // Track with wildcard - all controls of a device trackMqtt("/devices/wb-gpio/controls/+", function(message) { log("GPIO change: {} = {}", message.topic, message.value); }); // Track all devices with multi-level wildcard trackMqtt("/devices/#", function(message) { if (message.topic.indexOf("/controls/") > 0) { log("Device update: {} = {}", message.topic, message.value); } }); // Track custom application topics trackMqtt("/myapp/commands/#", function(message) { var command = JSON.parse(message.value); switch(command.action) { case "turn_on": dev[command.device + "/" + command.control] = true; break; case "turn_off": dev[command.device + "/" + command.control] = false; break; } }); // Track external sensor data trackMqtt("/sensors/+/temperature", function(message) { var sensorId = message.topic.split("/")[2]; log("Sensor {} temperature: {}", sensorId, message.value); dev["sensors-vdev/" + sensorId + "_temp"] = parseFloat(message.value); }); ``` -------------------------------- ### Load JSON Configuration Files with Comments in JavaScript Source: https://context7.com/wirenboard/wb-rules/llms.txt Loads and parses JSON configuration files, supporting comments. It expects the root element to be a JavaScript object and can handle missing files gracefully with error handling. ```javascript // Read configuration file var config = readConfig("/etc/wb-rules/myconfig.conf"); // Access configuration values log("Threshold: {}", config.threshold); log("Enabled: {}", config.enabled); // Configuration file example (/etc/wb-rules/myconfig.conf): // { // // Main settings // "threshold": 25.5, // "enabled": true, // "sensors": ["temp1", "temp2", "temp3"], // /* Notification settings */ // "notifications": { // "email": "admin@example.com", // "sms": "+71234567890" // } // } // Use configuration in rules var appConfig = readConfig("/etc/wb-rules/app.conf"); defineRule("configurable_threshold", { asSoonAs: function() { return dev["wb-w1/28-00000a000001"] > appConfig.threshold; }, then: function() { if (appConfig.notifications.email) { Notify.sendEmail(appConfig.notifications.email, "Alert", "Threshold exceeded"); } } }); // Handle missing config gracefully var optionalConfig; try { optionalConfig = readConfig("/etc/wb-rules/optional.conf"); } catch (e) { log.warning("Optional config not found, using defaults"); optionalConfig = { defaultValue: 10 }; } ``` -------------------------------- ### Configure and Load Alarms with Notifications - JavaScript Source: https://context7.com/wirenboard/wb-rules/llms.txt Defines and loads alarm configurations for monitoring device values and sending notifications. Supports various notification types (email, SMS, Telegram) and alarm conditions like expected values, ranges, intervals, and delays. Alarms are managed via a virtual device. ```javascript // Load alarms from configuration file Alarms.load("/etc/wb-rules/alarms.conf"); // Or define alarms inline Alarms.load({ deviceName: "monitoring-alarms", deviceTitle: { en: "Monitoring Alarms", ru: "Мониторинг" }, recipients: [ { type: "email", to: "admin@example.com", subject: "Alarm: {}" }, { type: "sms", to: "+71234567890" }, { type: "telegram", token: "1234567890:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", chatId: "123456789" } ], alarms: [ { name: "power_failure", cell: "ups/status", expectedValue: 1, alarmMessage: "UPS power failure detected!", noAlarmMessage: "UPS power restored" }, { name: "temperature_high", cell: "wb-w1/28-00000a000001", maxValue: 45, alarmMessage: "Temperature too high: {} °C", noAlarmMessage: "Temperature normal: {} °C", interval: 300, // Repeat notification every 5 minutes maxCount: 5, // Maximum 5 notifications per alarm alarmDelayMs: 10000, // Trigger after 10s of sustained condition noAlarmDelayMs: 5000 // Clear after 5s of normal condition }, { name: "humidity_range", cell: "wb-ms/Humidity", minValue: 30, maxValue: 70, alarmMessage: "Humidity out of range: {}%", noAlarmMessage: "Humidity normal: {}%" } ] }); // Check alarm status via virtual device if (dev["monitoring-alarms/alarm_temperature_high"]) { log.warning("Temperature alarm is active"); } ``` -------------------------------- ### Publish MQTT Messages with publish Source: https://context7.com/wirenboard/wb-rules/llms.txt Facilitates publishing messages to MQTT topics with configurable Quality of Service (QoS) levels and retain flag. It's commonly used for sending commands, status updates, or bridging data to other systems. ```javascript // Simple publish (QoS 0, not retained) publish("/myapp/status", "online"); // Publish with QoS publish("/myapp/events", JSON.stringify({ event: "started", time: Date.now() }), 1); // Publish retained message publish("/myapp/config/version", "1.2.3", 1, true); // Publish with maximum QoS and retained publish("/myapp/last_will", "Controller offline", 2, true); // Practical example: bridge to external system defineRule("bridge_temperature", { whenChanged: "wb-w1/28-00000a000001", then: function(newValue) { var payload = JSON.stringify({ sensor: "main_temperature", value: newValue, unit: "celsius", timestamp: Date.now() }); publish("/external/sensors/temperature", payload, 1, true); } }); // Publish using virtual device method var myDevice = defineVirtualDevice("mydev", { cells: { status: { type: "text", value: "" } } }); // This publishes to /devices/mydev/custom_topic getDevice("mydev").publish("custom_topic", "custom message"); ``` -------------------------------- ### Access Device Parameters with the `dev` Object in JavaScript Source: https://context7.com/wirenboard/wb-rules/llms.txt The `dev` object allows reading and writing device parameters using bracket or dot notation. Meta-properties like `#error`, `#readonly`, and `#type` can be accessed with a `#` suffix. Type conversion is handled automatically based on control type. This is crucial for device interaction and state management within rules. ```javascript var temperature = dev["wb-w1/28-00000a000001"]; var relayState = dev["wb-gpio"]["A1_OUT"]; var adcValue = dev.wbadc.A1; dev["wb-gpio/A1_OUT"] = true; dev["wb-mdm3"]["Relay 1"] = false; dev["dimmer/brightness"] = 75; var errorState = dev["wb-mr3_48/K1#error"]; var isReadonly = dev["somedev/control#readonly"]; var controlType = dev["somedev/control#type"]; dev["mydevice/control#error"] = "Connection lost"; dev["mydevice/control#max"] = 100; defineRule("relay_error_monitor", { whenChanged: "wb-mr3_48/K1#error", then: function(newValue, devName, cellName) { if (newValue !== "") { log.error("Relay error: {}", newValue); Notify.sendSMS("+71234567890", "Relay K1 error: " + newValue); } else { log.info("Relay K1 recovered"); } } }); defineRule("multi_sensor", { whenChanged: ["wb-gpio/A1_IN", "wb-gpio/A2_IN", "wb-adc/A1"], then: function(newValue, devName, cellName) { log("{}/{} changed to {}", devName, cellName, newValue); } }); ``` -------------------------------- ### Utilize CommonJS Modules for Reusable Code in JavaScript Source: https://context7.com/wirenboard/wb-rules/llms.txt Supports CommonJS-style modules for organizing reusable code. Modules export functionality via the `exports` object and can maintain static state across scripts. They can be loaded from user or system directories. ```javascript // Module file: /etc/wb-rules-modules/utils.js exports.celsiusToFahrenheit = function(celsius) { return celsius * 9/5 + 32; }; exports.formatTemperature = function(value, unit) { return value.toFixed(1) + " " + (unit || "°C"); }; exports.clamp = function(value, min, max) { return Math.min(Math.max(value, min), max); }; // Module with static state: /etc/wb-rules-modules/counter.js exports.increment = function() { if (module.static.count === undefined) { module.static.count = 0; } return ++module.static.count; }; exports.getCount = function() { return module.static.count || 0; }; // Module path info log("Module file: {}", module.filename); // Full path to module log("Script file: {}", __filename); // Script that loaded module // Using modules in scripts var utils = require("utils"); var counter = require("counter"); defineRule("temperature_report", { whenChanged: "wb-w1/28-00000a000001", then: function(newValue) { var celsius = newValue; var fahrenheit = utils.celsiusToFahrenheit(celsius); log("Temperature: {} ({})", utils.formatTemperature(celsius, "°C"), utils.formatTemperature(fahrenheit, "°F")); log("Update count: {}", counter.increment()); } }); // Submodule loading var submodule = require("mypackage/submodule"); // Loads mypackage/submodule.js ``` -------------------------------- ### Define Automation Rules with defineRule Source: https://context7.com/wirenboard/wb-rules/llms.txt Defines automation rules that trigger callback functions based on various conditions like device parameter changes, boolean expressions, or cron schedules. The `defineRule` function returns a rule ID for programmatic control (enable, disable, run). ```javascript // Rule triggered when a device parameter changes defineRule("temperature_monitor", { whenChanged: "wb-w1/28-00000a000001", then: function(newValue, devName, cellName) { log("Temperature changed: {}/{} = {}", devName, cellName, newValue); if (newValue > 30) { dev["wb-gpio/A1_OUT"] = true; // Turn on cooling fan } } }); // Rule triggered when condition becomes true (edge-triggered) defineRule("start_heating", { asSoonAs: function() { return dev["wb-w1/28-00000a000001"] < 18; }, then: function() { log("Starting heater - temperature below threshold"); dev["wb-gpio/A2_OUT"] = true; } }); // Rule triggered continuously while condition is true (level-triggered) defineRule("monitor_pressure", { when: function() { return dev["wb-adc/A1"] > 3.3; }, then: function() { log.warning("High pressure detected!"); } }); // Rule triggered on schedule using cron syntax defineRule("daily_report", { when: cron("0 0 8 * * *"), // Every day at 8:00 AM then: function() { log("Generating daily report"); Notify.sendEmail("admin@example.com", "Daily Report", "System status: OK"); } }); // Controlling rules programmatically var myRule = defineRule("controllable_rule", { whenChanged: "somedev/control", then: function() { log("Rule executed"); } }); disableRule(myRule); // Disable rule checking enableRule(myRule); // Re-enable rule runRule(myRule); // Force execute the rule's then function ``` -------------------------------- ### Manage Persistent Key-Value Storage Across Reboots - JavaScript Source: https://context7.com/wirenboard/wb-rules/llms.txt Provides a key-value storage mechanism that persists data across controller reboots using BoltDB. Supports storing primitive types and complex objects via StorableObject. Data can be read, written, and deleted by setting values to null or undefined. ```javascript // Create a global persistent storage var storage = new PersistentStorage("my-storage", { global: true }); // Store primitive values storage["counter"] = 42; storage["last_runtime"] = Date.now(); storage["device_name"] = "Controller-1"; // Read values var counter = storage["counter"]; log("Counter value: {}", counter); // Delete value by setting to null or undefined storage["temporary"] = "some value"; storage["temporary"] = null; // Deletes the key // Store objects using StorableObject storage["settings"] = new StorableObject({ threshold: 25, enabled: true, sensors: ["temp1", "temp2"] }); // Modify stored object (changes are persisted automatically) var settings = storage["settings"]; settings.threshold = 30; settings.enabled = false; // Practical example: track runtime statistics defineRule("track_runtime", { when: cron("0 * * * * *"), // Every minute then: function() { var stats = storage["runtime_stats"]; if (!stats) { storage["runtime_stats"] = new StorableObject({ startTime: Date.now(), minutesRunning: 0 }); stats = storage["runtime_stats"]; } stats.minutesRunning++; log("System running for {} minutes", stats.minutesRunning); } }); // Multiple storages for different purposes var configStorage = new PersistentStorage("config", { global: true }); var stateStorage = new PersistentStorage("state", { global: true }); configStorage["alarm_threshold"] = 50; stateStorage["last_alarm_time"] = Date.now(); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.