Peripheral Execution Configuration
Peripheral Execution Configuration
This document is intended for device configuration users / integrators and covers the configuration methods for Peripheral Execution Rules (PeriphExec Rule), usage differences between trigger and action types, field semantics, and typical scenarios.
If you are interested in low-level implementation architecture, task scheduling, and source code logic, please read
periph-exec-flow.md.If you are interested in the peripherals themselves (types, pins, compile switches), please read
peripheral-configuration-guide.md.
Current Version Notes
- The Lite edition retains peripheral execution capability by default but disables Command Script and RuleScript; script actions require Standard, Full, or custom builds.
- Event triggers now support local sensor data sources; event IDs use the
ds:<sourceId>format, e.g.ds:dht_01_temperature. - The "Local Sensor" dropdown only shows data sources that have been configured via sensor read actions in peripheral execution rules; no invalid sensor sources are displayed when no read action is configured.
- The default configuration no longer includes a dedicated buzzer peripheral or buzzer preset actions;
actionType=20is retained as a historical placeholder. - Display actions are grouped under the "Display" category in the Web UI, retaining four action types: Display Number, Display Text, Clear Display, and OLED Custom Display for easy selection.
- For configuration backup and migration, use "Device Config > Advanced Config > Config Import/Export" to import/export
periph_exec.jsonindividually under "Peripheral Execution".
The Peripheral Execution page displays the rule list, enable status, trigger and action entries. When creating a new rule, keep it disabled first, then confirm action safety via "Run Once" and logs after saving.
| Name | Status | Trigger | Target Peripheral | Action | Stats | Operations |
|---|---|---|---|---|---|---|
| ADC Voltage Read & Report | Disabled | Timer Trigger | ADC Analog Convert | Sensor Data Read -> ADC Analog Convert | Triggered: 1 | Run Once / Edit / Enable / Delete |
| ADC Voltage Below 2.30V Close Relay | Disabled | Event Trigger | - | Set LOW | Triggered: 1 | Run Once / Edit / Enable / Delete |
| ADC Voltage Above 2.50V Open Relay | Disabled | Event Trigger | - | Set HIGH | Triggered: 1 | Run Once / Edit / Enable / Delete |
| ADC Voltage Display on 7-Segment | Disabled | Timer Trigger | - | Display Number | Triggered: 1 | Run Once / Edit / Enable / Delete |
| NTP Time Sync | Disabled | Platform Trigger (MQTT) | - | NTP Sync | Triggered: 1 | Run Once / Edit / Enable / Delete |
| OLED Temp & Humidity Display | Disabled | Timer Trigger | - | OLED Custom Display | Triggered: 1 | Run Once / Edit / Enable / Delete |
| OLED Custom Display - Button Trigger Device Info | Disabled | Event Trigger | - | OLED Custom Display | Triggered: 1 | Run Once / Edit / Enable / Delete |
| OLED Custom Display - Timer Mixed | Disabled | Timer Trigger | - | OLED Custom Display | Triggered: 1 | Run Once / Edit / Enable / Delete |
| OLED Custom Display - MQTT Message | Disabled | Platform Trigger (MQTT) | - | OLED Custom Display | Triggered: 1 | Run Once / Edit / Enable / Delete |
| OTA Upgrade | Disabled | Platform Trigger (MQTT) | - | OTA Upgrade | Triggered: 1 | Run Once / Edit / Enable / Delete |
When configuring, follow the chain diagram from left to right: first confirm the trigger source, then select the action target, and finally decide whether to report execution results; for complex rules, save as disabled first, then enable after manual execution confirms safety.
Before going live, follow the lifecycle diagram: save as disabled first, check trigger and action parameters, manually execute to confirm safety, then enable auto-trigger; in case of anomalies, disable the rule and restore backup first.
When configuring a rule, first answer "when to execute", then "what action to perform". Keep triggers single and clear; start actions with observable, reversible single actions.
| Trigger | Input Source | Check Timing | Suitable Scenarios | Common Risks |
|---|---|---|---|---|
| Platform Trigger | MQTT / HTTP / Cloud commands | Match fields immediately on message arrival | Remote switch, parameter delivery, interlocking control | Field name mismatch, messageId duplication, insufficient permissions |
| Timer Trigger | Local clock / cron / interval | Execute when time point is reached | Periodic reporting, timed switching, night mode | NTP not synced, first trigger semantics unclear |
| Event Trigger | Buttons, sensors, system events | Match eventId on event publish | Button control, threshold alarm, state change | Debounce, event name typos, stale cache values |
| Poll Trigger | Active reading of peripheral or protocol data | Check conditions every pollInterval | Modbus collection, analog threshold, distance alarm | Too frequent, serial port busy, low-memory frequency reduction |
Choosing the wrong trigger type will lead you astray in troubleshooting. For platform triggers, check platform messages and protocol connectivity; for timer triggers, check clock and interval; for event triggers, check event ID and debounce; for poll triggers, check sampling period, timeout, retries, and resource usage.
| Check Item | Confirm Before Enabling | Risk Note |
|---|---|---|
| Basic Info | Name is identifiable, ID is unique, save as disabled first, note field conditions | Make the rule an auditable object before entering individual verification. |
| Triggers | Source is clear, conditions are reproducible, poll interval is reasonable, event name is accurate | Do not mix up platform, timer, event, and poll troubleshooting paths. |
| Actions | Target peripheral exists, actionType is correct, actionValue is valid, strong actions have been confirmed | Manually execute relays, motors, and register writes once first. |
| Results & Reporting | Logs are traceable, reporting fields are correct, failures have responses, screenshots available | Check not only device actions but also what the platform receives. |
| Rollback | Can disable, has backup, knows recovery entry, on-site power-off point is clear | Keep a physical emergency stop for dangerous actions. |
Before enabling rules, check basic info, triggers, actions, result reporting, and rollback methods against the diagram. When there is a real load on-site, strong-action rules must be saved as disabled and manually verified first.
Table of Contents
- 1. What Is a Peripheral Execution Rule
- 2. Rule Structure Overview
- 3. Trigger Details
- 4. Action Details
- 4.1 GPIO Output Actions (0/1/13/14)
- 4.2 PWM / Analog Output Actions (2/3/4/5)
- 4.3 System Management Actions (6/7/8/9)
- 4.4 Call / Script Actions (10/15)
- 4.5 Modbus Actions (16/17/18)
- 4.6 Data / Event Actions (19/21)
- 4.7 Rule Control Actions (22/23)
- 4.8 Display Actions (24/25/26/27)
- 4.9 Complete Action Type Quick Reference
- 5. Templates & Dynamic Values
- 6. Should Display Actions Be Merged? Assessment
- 7. Typical Configuration Examples
- 8. Best Practices
- 9. FAQ
1. What Is a Peripheral Execution Rule
A Peripheral Execution Rule (PeriphExec Rule) is the local automation rule engine of FastBee devices, implementing the logic loop of "when a condition is met, execute a set of actions" without relying on cloud linkage. It works even when offline.
A rule consists of three parts:
┌─────────────┐ ┌────────────────┐ ┌─────────────┐
│ Triggers │ ──> │ Condition / │ ──> │ Actions │
│ (multiple) │ │ Received Value │ │ (multiple) │
│ OR logic │ │ Template parse │ │ Sequential │
└─────────────┘ └────────────────┘ └─────────────┘- Triggers: Up to 3; any match triggers the rule (OR logic).
- Actions: Up to 4; executed sequentially in array order (each action can have a delay
syncDelayMs). - Execution Mode (execMode):
0=async(default, FreeRTOS task, non-blocking) /1=sync(blocking execution, suitable for fast IO).
Configuration file path: /config/periph_exec.json, loaded by PeriphExecManager at runtime.
2. Rule Structure Overview
Single rule JSON structure (one item in the data/config/periph_exec.json array):
When reading JSON, cross-reference the data model: top-level fields describe rule identity and execution strategy, triggers describe source and conditions, actions describe target peripheral and action parameters, and reportAfterExec determines whether observable feedback is generated after execution.
{
"id": "exec_1700000000001",
"name": "High Temperature Alarm",
"enabled": true,
"execMode": 0,
"triggers": [
{
"triggerType": 5,
"triggerPeriphId": "dht_01",
"operatorType": 2,
"compareValue": "30"
}
],
"actions": [
{ "targetPeriphId": "fan_01", "actionType": 0, "execMode": 1 },
{ "targetPeriphId": "lcd_01", "actionType": 27, "actionValue": "# High Temp Alarm\nTemp: ${dht_01.temperature}°C", "syncDelayMs": 200 }
],
"protocolType": 0,
"scriptContent": "",
"reportAfterExec": true
}2.1 Top-Level Fields
| Field | Type | Default | Description |
|---|---|---|---|
id | string | — | Unique ID (recommended exec_ prefix + timestamp) |
name | string | — | Display name (used in UI / logs) |
enabled | bool | true | Rule enable switch |
execMode | 0|1 | 0 | Rule-level execution mode: 0=async, 1=sync; action-level execMode overrides if set |
triggers | array | — | Trigger list, max 3, OR logic |
actions | array | — | Action list, max 4, sequential execution |
protocolType | uint8 | 0 | Data reporting protocol preference: 0=MQTT, 1=ModbusRTU, 2=ModbusTCP, 3=HTTP, 4=CoAP, 5=TCP |
scriptContent | string | "" | Optional text template for data reshaping after execution (${key} placeholders) |
reportAfterExec | bool | true | Whether to auto-report control results to the enabled protocol after execution |
Compatibility Note: Older firmware may store unset
scriptContentas the string"null"; the current version auto-corrects this to an empty string. No manual handling needed after upgrade.
Quota Limits: A single rule's
triggersmust not exceed 3 (MAX_TRIGGERS_PER_RULE), andactionsmust not exceed 4 (MAX_ACTIONS_PER_RULE). Exceeding these will be rejected on save.
3. Trigger Details
triggerType values: 0=Platform Trigger, 1=Timer Trigger, 4=Event Trigger, 5=Poll Trigger.
Note: Historical values
2=DATA_RECEIVEand3=DATA_REPORTare deprecated and unified into4=Event Trigger(use eventId to differentiate).
3.1 Platform Trigger (PLATFORM_TRIGGER=0)
Purpose: Respond to IoT platform MQTT property set / function call commands.
Fields:
| Field | Description |
|---|---|
triggerPeriphId | Required. Exact match with MQTT message item.id (usually peripheral ID) |
operatorType | Comparison operator, special semantics see below |
compareValue | Comparison value; when operatorType=1, means "set mode" with no comparison, any value matches |
operatorType Special Convention (Platform Trigger Only):
0= Exact match: triggers only whenitem.value == compareValue(e.g., only responds to commands withvalue="ON")1= Set mode: no value comparison, triggers as long asitem.id == triggerPeriphId, and injectsitem.valueasreceivedValueinto subsequent actions
Other
operatorTypevalues (2=GT/3=LT/4=GTE/5=LTE/6=BETWEEN/7=NOT_BETWEEN/8=CONTAIN/9=NOT_CONTAIN) are commonly used only with poll triggers; platform triggers typically use only 0/1.
Typical Configuration:
{ "triggerType": 0, "triggerPeriphId": "relay_01", "operatorType": 1, "compareValue": "" }Meaning: Receiving platform commands {"id":"relay_01","value":"ON"} or {"id":"relay_01","value":"OFF"} will both trigger; actions can use the $value placeholder to read the delivered value.
3.2 Timer Trigger (TIMER_TRIGGER=1)
Purpose: Periodic execution by interval or daily time point.
Fields:
| Field | Description |
|---|---|
timerMode | 0=Interval (every N seconds) / 1=Daily time point (HH:MM) |
intervalSec | Interval in seconds (effective when timerMode=0, minimum 1s, recommended ≥5s to avoid frequent wake-ups) |
timePoint | "HH:MM" (effective when timerMode=1, 24h format; requires NTP time sync) |
Typical Configuration:
// Refresh OLED every 15 seconds
{ "triggerType": 1, "timerMode": 0, "intervalSec": 15 }
// Trigger watering every day at 6:30 AM
{ "triggerType": 1, "timerMode": 1, "timePoint": "06:30" }Daily time point trigger depends on system time; NTP is strongly recommended. No trigger fires before time is synced (
getLocalTime()fails).
3.3 Event Trigger (EVENT_TRIGGER=4)
Purpose: Respond to system events (WiFi/MQTT/NTP/buttons/OTA/peripheral execution completion/protocol data send/receive, etc.).
Fields:
| Field | Description |
|---|---|
eventId | Required. Event ID string (see table below) |
Common Event ID Quick Reference (full list in include/core/PeripheralExecution.h STATIC_EVENTS):
| Category | eventId | Description |
|---|---|---|
| WiFi | wifi_connected / wifi_disconnected / wifi_conn_failed | WiFi connection state |
| MQTT | mqtt_connected / mqtt_disconnected / mqtt_enabled | MQTT protocol state |
| Network Mode | net_mode_ap / net_mode_sta | AP/STA switch |
| System | ntp_synced / ota_start / ota_success / ota_failed | System services |
| System State | system_boot / system_ready / system_error / factory_reset | Lifecycle |
| Button | button_click / button_double_click / button_long_press_2s / button_long_press_5s / button_long_press_10s / button_press / button_release | Button detection from digital input pull-up/pull-down pins (50ms debounce, 200ms double-click window) |
| Rule | periph_exec_completed | Fires when any peripheral execution rule completes |
| Data | data_receive / data_report | Protocol data send/receive (replaces deprecated 2/3) |
| Device Events | break_down / restart / device_alarm / low_power | Can be actively emitted by rules for MQTT reporting |
| Custom Events | IDs from DEVICE_EVENT peripherals (type=60) | User-defined events, can be emitted by ACTION_TRIGGER_EVENT |
| Modbus Control Events | mc:<slaveId>:<regAddr> | Control events on Modbus slave register write; use compareValue to match specific written values |
Typical Configuration:
// Light up LED after WiFi connects
{ "triggerType": 4, "eventId": "wifi_connected" }
// Toggle relay on button double-click
{ "triggerType": 4, "eventId": "button_double_click", "triggerPeriphId": "btn_01" }Button events also support
triggerPeriphIdfiltering: only button events from that peripheral ID will match. Leave empty to match all buttons.
3.4 Poll Trigger (POLL_TRIGGER=5)
Purpose: Locally and periodically read sensor / Modbus slave data; triggers when readings meet conditions.
Fields:
| Field | Description |
|---|---|
triggerPeriphId | Required. Data source peripheral ID (can be DHT/DS18B20/Modbus slave/ADC, etc.) |
operatorType | Condition operator (0=EQ / 1=NEQ / 2=GT / 3=LT / 4=GTE / 5=LTE / 6=BETWEEN / 7=NOT_BETWEEN / 8=CONTAIN / 9=NOT_CONTAIN) |
compareValue | Comparison threshold; BETWEEN/NOT_BETWEEN uses "min,max" format (e.g., "20,30") |
intervalSec | Poll period in seconds (recommended ≥5s; <5s is corrected by safety lower limit) |
pollResponseTimeout | Modbus response timeout (ms), default 1000 |
pollMaxRetries | Modbus max retries, default 2 |
pollInterPollDelay | Minimum interval between multiple slaves on the same bus (ms), default 100 |
Typical Configuration:
// Trigger when temperature > 30°C (DHT11 polls every 30 seconds)
{
"triggerType": 5,
"triggerPeriphId": "dht_01",
"operatorType": 2,
"compareValue": "30",
"intervalSec": 30
}
// Alert when Modbus slave register value is outside [1000, 2000]
{
"triggerType": 5,
"triggerPeriphId": "mb_slave_01",
"operatorType": 7,
"compareValue": "1000,2000",
"intervalSec": 10,
"pollResponseTimeout": 1500,
"pollMaxRetries": 3
}Performance Tip: Poll triggers bind hardware tasks. Too many active poll tasks (>8) or too short intervals (<5s) will trigger safety correction logs. For Modbus polling, also note serial bus contention; recommend
pollInterPollDelay ≥ 100msbetween multiple slaves.
3.5 Trigger Type Comparison Table
| Dimension | Platform (0) | Timer (1) | Event (4) | Poll (5) |
|---|---|---|---|---|
| Trigger Source | IoT platform MQTT delivery | System clock | System/button/protocol events | Local sensor periodic reading |
| Works Offline | ❌ Requires MQTT online | ✅ Fully offline | ✅ All local events supported | ✅ Fully offline |
receivedValue Source | Platform-delivered value | None | Event-attached data (can be empty) | Local reading |
| Key Fields | triggerPeriphId + operatorType+compareValue | timerMode + intervalSec / timePoint | eventId (optional triggerPeriphId) | triggerPeriphId + operatorType + compareValue + intervalSec |
| Typical Scenarios | Remote control, remote parameter setting | Timed watering, timed display refresh | WiFi disconnect alarm, button toggle, OTA completion alert | Temperature control, threshold alarm, local interlocking |
| Recommended Period Lower Limit | — | ≥1s (recommended ≥5s) | Event-driven, no period | ≥5s (below is corrected) |
4. Action Details
All actions are written into the same array and executed in index order. Each action can carry syncDelayMs (pre-execution delay, max 10000ms) for timing orchestration.
4.1 GPIO Output Actions (0/1/13/14)
| actionType | Name | actionValue | Target | Description |
|---|---|---|---|---|
0 | ACTION_HIGH | — | GPIO_DIGITAL_OUTPUT | Set HIGH |
1 | ACTION_LOW | — | GPIO_DIGITAL_OUTPUT | Set LOW |
13 | ACTION_HIGH_INVERTED | — | GPIO_DIGITAL_OUTPUT | "Logic HIGH" but physical output LOW (for active-low relays) |
14 | ACTION_LOW_INVERTED | — | GPIO_DIGITAL_OUTPUT | "Logic LOW" but physical output HIGH |
Purpose of inverted actions: Some relay modules are "active-low driven"; using
ACTION_HIGHdirectly would turn them off.ACTION_HIGH_INVERTEDmaintains the "HIGH = ON" semantic intuition.
4.2 PWM / Analog Output Actions (2/3/4/5)
| actionType | Name | actionValue Format | Target |
|---|---|---|---|
2 | ACTION_BLINK | Blink period ms (e.g., "500") | PWM/GPIO output |
3 | ACTION_BREATHE | Breathe period ms (e.g., "2000") | PWM output |
4 | ACTION_SET_PWM | Duty cycle 0-255 or percentage 0-100 | GPIO_PWM_OUTPUT |
5 | ACTION_SET_DAC | DAC value 0-255 | DAC (ESP32 DAC-supported pins only) |
When
useReceivedValue=trueis enabled,actionValueis overridden by the trigger source's received value, suitable for platform-delivered brightness/duty cycle, etc.
4.3 System Management Actions (6/7/8/9)
| actionType | Name | targetPeriphId | actionValue |
|---|---|---|---|
6 | ACTION_SYS_RESTART | Can be empty | — |
7 | ACTION_SYS_FACTORY_RESET | Can be empty | — |
8 | ACTION_SYS_NTP_SYNC | Can be empty | Optional NTP server |
9 | ACTION_SYS_OTA | Can be empty | Firmware URL |
System actions do not require
targetPeriphIdas they affect the entire device. Place them at the end of the action list (to prevent subsequent actions from failing due to restart).
4.4 Call / Script Actions (10/15)
| actionType | Name | Description |
|---|---|---|
10 | ACTION_CALL_PERIPHERAL | Forwards actionValue as a command to the targetPeriphId peripheral; stepper motors support JSON commands |
15 | ACTION_SCRIPT | Executes a command sequence script; actionValue is the script content. See script-guide.md |
Stepper motors (STEPPER_MOTOR, type=42) are recommended to use JSON format to avoid command parameter ambiguity:
| actionValue Example | Description |
|---|---|
{"periphId":"stepper","action":"forward"} | Forward |
{"periphId":"stepper","action":"reverse"} | Reverse |
{"periphId":"stepper","action":"stop"} | Stop and release coils |
{"periphId":"stepper","action":"faster","value":"2"} | Speed up by 2 RPM |
{"periphId":"stepper","action":"slower","value":"2"} | Slow down by 2 RPM |
{"periphId":"stepper","action":"setSpeed","value":"12"} | Set speed to 12 RPM |
4.5 Modbus Actions (16/17/18)
| actionType | Name | actionValue | Description |
|---|---|---|---|
16 | ACTION_MODBUS_COIL_WRITE | "coilAddr:0/1" or standalone "0/1" | Modbus FC05 write coil |
17 | ACTION_MODBUS_REG_WRITE | "regAddr:value" or standalone "value" | Modbus FC06 write register |
18 | ACTION_MODBUS_POLL | None | Actively trigger one slave data collection (scheduled by PeriphExec) |
targetPeriphIdmust be a configured Modbus slave device (MODBUS_DEVICE, type=51).
4.6 Data / Event Actions (19/21)
| actionType | Name | actionValue | Target |
|---|---|---|---|
19 | ACTION_SENSOR_READ | — | Sensors (DHT/DS18B20/ADC/pulse), used to actively trigger one collection and cache |
21 | ACTION_TRIGGER_EVENT | Event extra data (can be empty) | targetPeriphId = event ID (system built-in or DEVICE_EVENT peripheral ID) |
ACTION_TRIGGER_EVENTis used for inter-rule linkage: one rule can act as an event source to wake other rules triggered by that event.
4.7 Rule Control Actions (22/23)
| actionType | Name | targetPeriphId | Description |
|---|---|---|---|
22 | ACTION_ENABLE_EXEC_RULE | id of another rule | Enable that rule |
23 | ACTION_DISABLE_EXEC_RULE | id of another rule | Disable that rule |
Used for mode switching: e.g., button long-press 5s to toggle "Day Mode" / "Night Mode" (enable one set of rules while disabling another).
4.8 Display Actions (24/25/26/27)
| actionType | Name | actionValue | Target Peripheral Type | Compile Switch |
|---|---|---|---|---|
24 | ACTION_DISPLAY_NUMBER | Number: "12.34" / "12:34" / "1234" / "-12", supports ${id.field} | SEVEN_SEGMENT_TM1637 (47) | FASTBEE_ENABLE_SEVEN_SEGMENT |
25 | ACTION_DISPLAY_TEXT | Text (max 4 chars, limited charset), supports ${id.field} | SEVEN_SEGMENT_TM1637 (47) | FASTBEE_ENABLE_SEVEN_SEGMENT |
26 | ACTION_DISPLAY_CLEAR | — | SEVEN_SEGMENT_TM1637 (47) | FASTBEE_ENABLE_SEVEN_SEGMENT |
27 | ACTION_OLED_DISPLAY | Multi-line text, supports ${id.field} + $value; first line # prefix = centered title + separator; \n line break; max 512 chars | LCD (36) | FASTBEE_ENABLE_LCD |
Note:
targetPeriphIdmust match the corresponding hardware type; mismatch (e.g., assigning 24 to an LCD peripheral) will be rejected at runtime with awarninglog. See Chapter 6 Merge Assessment.
4.9 Complete Action Type Quick Reference
| ID | Name | Category | Key Parameters |
|---|---|---|---|
| 0 | ACTION_HIGH | GPIO | — |
| 1 | ACTION_LOW | GPIO | — |
| 2 | ACTION_BLINK | PWM | Period ms |
| 3 | ACTION_BREATHE | PWM | Period ms |
| 4 | ACTION_SET_PWM | PWM | 0-255 / 0-100% |
| 5 | ACTION_SET_DAC | DAC | 0-255 |
| 6 | ACTION_SYS_RESTART | System | — |
| 7 | ACTION_SYS_FACTORY_RESET | System | — |
| 8 | ACTION_SYS_NTP_SYNC | System | NTP server |
| 9 | ACTION_SYS_OTA | System | Firmware URL |
| 10 | ACTION_CALL_PERIPHERAL | Communication | Command string |
| 13 | ACTION_HIGH_INVERTED | GPIO | — |
| 14 | ACTION_LOW_INVERTED | GPIO | — |
| 15 | ACTION_SCRIPT | Script | Script text |
| 16 | ACTION_MODBUS_COIL_WRITE | Modbus | addr:val |
| 17 | ACTION_MODBUS_REG_WRITE | Modbus | addr:val |
| 18 | ACTION_MODBUS_POLL | Modbus | — |
| 19 | ACTION_SENSOR_READ | Data | — |
| 20 | Reserved | — | Legacy buzzer preset removed |
| 21 | ACTION_TRIGGER_EVENT | Event | Event data |
| 22 | ACTION_ENABLE_EXEC_RULE | Rule Control | Rule ID |
| 23 | ACTION_DISABLE_EXEC_RULE | Rule Control | Rule ID |
| 24 | ACTION_DISPLAY_NUMBER | Display | Number string |
| 25 | ACTION_DISPLAY_TEXT | Display | ≤4 chars |
| 26 | ACTION_DISPLAY_CLEAR | Display | — |
| 27 | ACTION_OLED_DISPLAY | Display | Multi-line + template |
5. Templates & Dynamic Values
Action actionValue supports three dynamic value mechanisms:
5.1 ${periphId.field} Sensor Template
Reads the latest value from the local sensor data cache and substitutes it.
Supported fields (by sensor type):
- DHT11 / DHT22:
temperature/humidity - DS18B20:
temperature - Analog input (ADC / GPIO_ANALOG_INPUT):
value/voltage - Digital input:
value(0/1) - Modbus slave:
reg_<N>/coil_<N>
Example:
"# Environment Monitor\nTemp: ${dht_01.temperature}°C\nHumidity: ${dht_01.humidity}%"5.2 $value Received Value Placeholder (OLED Action 27 Only)
Replaced with the original value from the trigger source:
- Platform trigger: MQTT-delivered
item.value - Poll trigger: Current peripheral reading
- Event trigger: Event-attached data
Example:
"# Platform Delivery\nValue: $value"When MQTT delivers {"id":"lcd_01","value":"Hello"}, it displays Value: Hello.
5.3 useReceivedValue=true (Universal)
When this flag is set on an ExecAction, the entire actionValue is completely replaced by the "received value" (suitable for PWM/DAC/relays directly using platform-delivered numbers).
6. Should Display Actions Be Merged? Assessment
The community has proposed "merging Display Number (24) / Display Text (25) / Clear Display (26) / OLED Custom Display (27) into a single universal action to simplify configuration". After assessment, the current 4 independent actions are retained for the following reasons:
6.1 Fundamental Hardware Differences
| Dimension | TM1637 (24/25/26) | OLED/LCD (27) |
|---|---|---|
| Driver Layer | SevenSegmentDriver (bit-bang) | LCDManager (U8g2 graphics library) |
| Display Capability | 4-digit 7-segment (limited charset) | 128×64 graphics matrix, multi-line text |
| Parameter Format | Simple string | Multi-line + template + # title + \n |
| Compile Switch | FASTBEE_ENABLE_SEVEN_SEGMENT | FASTBEE_ENABLE_LCD |
| UI Control | <input> | <textarea rows=6 maxlength=512> |
6.2 Problems Caused by Merging
- Parameter validation complexity: After merging, the executor must implicitly determine field semantics based on
targetperipheral type, making error messages hard to pinpoint. - Breaking compatibility: Existing configurations with
actionType=24/25/26/27would need migration scripts. - Frontend forms would be more complex: A "universal display" action would require extensive conditional rendering (target type → parameter controls), harder to maintain than the current 4 independent actions.
6.3 Current Compromise Solution
"Frontend categorical merge + backend remains independent":
- The frontend UI (
web-src/modules/runtime/periph-exec-form.js) groups all four actions under the "Display" category (periph-exec-action-cat-display); users see them in the same dropdown category. - Parameter controls automatically switch based on
actionType: 24/25 useinput, 26 has no parameters, 27 usestextarea. - Backend enums remain independent; logs are clear; runtime type validation is strict (peripheral type mismatch is rejected immediately).
6.4 Optional Further Simplification (Future Optimization)
If reducing user selection cost is still desired, the recommended approach is to enhance the frontend only (no backend changes):
User first selects
targetPeriphId→ frontend only shows corresponding actions based on target peripheral type:
- Selected
SEVEN_SEGMENT_TM1637→ only show 24/25/26- Selected
LCD→ only show 27
With this approach, from the user's perspective it feels like "there's only one display action", while keeping the backend unchanged. This is the recommended progressive optimization path.
7. Typical Configuration Examples
7.1 Periodic OLED Environment Monitor Refresh
{
"id": "exec_oled_env",
"name": "OLED Environment Monitor (15s)",
"enabled": true,
"triggers": [
{ "triggerType": 1, "timerMode": 0, "intervalSec": 15 }
],
"actions": [
{
"targetPeriphId": "lcd_01",
"actionType": 27,
"actionValue": "# Environment Monitor\nTemp: ${dht_01.temperature}°C\nHumidity: ${dht_01.humidity}%\nIP: ${sys.ip}"
}
]
}7.2 Button Double-Click Toggle Relay
{
"id": "exec_btn_relay_toggle",
"name": "Button Double-Click Toggle Relay",
"enabled": true,
"triggers": [
{ "triggerType": 4, "eventId": "button_double_click", "triggerPeriphId": "btn_01" }
],
"actions": [
{ "targetPeriphId": "relay_01", "actionType": 15, "actionValue": "toggle relay_01" }
]
}7.3 High Temperature Alarm (Fan + OLED + MQTT Event Report)
{
"id": "exec_high_temp_alarm",
"name": "High Temp Alarm",
"enabled": true,
"triggers": [
{ "triggerType": 5, "triggerPeriphId": "dht_01", "operatorType": 2, "compareValue": "32", "intervalSec": 10 }
],
"actions": [
{ "targetPeriphId": "fan_01", "actionType": 0, "execMode": 1 },
{ "targetPeriphId": "lcd_01", "actionType": 27, "actionValue": "# High Temp Alarm\nTemp: ${dht_01.temperature}°C\nPlease ventilate", "syncDelayMs": 200 },
{ "targetPeriphId": "device_alarm", "actionType": 21, "actionValue": "temp_high" }
]
}7.4 Platform-Delivered PWM Brightness Control
{
"id": "exec_platform_pwm",
"name": "Platform Light Strip Brightness",
"enabled": true,
"triggers": [
{ "triggerType": 0, "triggerPeriphId": "pwm_led", "operatorType": 1, "compareValue": "" }
],
"actions": [
{ "targetPeriphId": "pwm_led", "actionType": 4, "actionValue": "128", "useReceivedValue": true }
]
}When platform delivers
{"id":"pwm_led","value":"200"}, PWM duty cycle is set to 200 (useReceivedValuecausesactionValueto be overridden by the received value).
7.5 WiFi Disconnect Alarm + OLED Display
{
"id": "exec_wifi_lost",
"name": "WiFi Disconnect Alarm",
"enabled": true,
"triggers": [
{ "triggerType": 4, "eventId": "wifi_disconnected" }
],
"actions": [
{ "targetPeriphId": "status_led", "actionType": 2, "actionValue": "500" },
{ "targetPeriphId": "lcd_01", "actionType": 27, "actionValue": "# Network Error\nWiFi Disconnected\nSystem will auto-reconnect", "syncDelayMs": 300 }
]
}7.6 Periodic 7-Segment Display Time (TM1637)
{
"id": "exec_tm1637_time",
"name": "7-Segment Display Time",
"enabled": true,
"triggers": [
{ "triggerType": 1, "timerMode": 0, "intervalSec": 30 }
],
"actions": [
{ "targetPeriphId": "tm1637_01", "actionType": 24, "actionValue": "${sys.time_hhmm}" }
]
}7.7 Button Long-Press 5s Toggle Day/Night Mode (Rule Linkage)
{
"id": "exec_mode_switch",
"name": "Long-Press Mode Switch",
"enabled": true,
"triggers": [
{ "triggerType": 4, "eventId": "button_long_press_5s", "triggerPeriphId": "btn_01" }
],
"actions": [
{ "targetPeriphId": "exec_day_mode", "actionType": 23 },
{ "targetPeriphId": "exec_night_mode", "actionType": 22 }
]
}8. Best Practices
8.1 Trigger Type Selection
| Scenario | Recommended Trigger |
|---|---|
| Platform remote control | Platform Trigger (0) |
| Periodic display refresh / collection reporting | Timer Trigger (1) |
| WiFi/MQTT/button system state changes | Event Trigger (4) |
| Local sensor threshold alarm | Poll Trigger (5) |
8.2 Performance & Resources
- Poll interval ≥ 5 seconds: Below 5s is corrected by
validateRuntimeConfig; Modbus polling recommended ≥ 10s. - Active async tasks ≤ 3:
MAX_ASYNC_TASKS=3; excess is queued. For dense rules, consider usingexecMode=1synchronous execution for simple GPIO actions. - Avoid rules waking each other in loops: When using
ACTION_TRIGGER_EVENTwithEVENT_PERIPH_EXEC_COMPLETED, add guard conditions to prevent infinite loops.
8.3 Orchestration & Timing
- Multiple actions execute sequentially in array order; use
syncDelayMsfor simple orchestration (e.g., turn on fan first, then refresh screen). syncDelayMsmax is 10000ms; for longer waits, split into two rules + event bridging.
8.4 Template Usage
- OLED multi-line templates with
#at the start of the first line produce a centered title + separator line, improving readability. - For sensor data field names, refer to each sensor chapter in
peripheral-configuration-guide.md. $valueis only enabled in OLED action 27; for other actions needing received values, useuseReceivedValue=true.
8.5 Persistence & Backup
- Configuration file
/config/periph_exec.jsonis on LittleFS; recommend periodic backup export via the UI's "Import/Export" feature. - When batch adding/removing rules, keep an eye on file size (long-term observation suggests ≤ 32KB is safe, depending on LittleFS partition).
9. FAQ
Q1: Why isn't my rule triggering?
Check each item:
- Is the rule
enabledset totrue? - Does the trigger type match (e.g., event trigger missing
eventId)? - Are the corresponding compile switches enabled (e.g., Modbus actions need
FASTBEE_ENABLE_MODBUS_RTU/TCP)? - Are there
[PeriphExec]related warnings in device logs (data/logs/system.log)? - For poll triggers, can the sensor read correctly (test manually in UI)?
Q2: What happens if OLED action (27) targets a TM1637 peripheral?
The runtime executor logs warning: "OLED_DISPLAY target '%s' is not LCD" and returns failure immediately. The UI form also filters available targetPeriphId based on actionType. Always match action type to target peripheral type.
Q3: How to display MQTT-delivered values on OLED?
Two steps:
- Use platform trigger with
operatorType=1(set mode, no comparison). - Include
$valueplaceholder in action 27'sactionValue.
When {"id":"lcd_01","value":"Hello"} is delivered, $value in the display text is replaced with Hello.
Q4: Can I set poll trigger period to 1 second?
Not recommended. The system corrects <5s periods to the absolute lower limit of 5s. For Modbus slave polling with multiple devices on the bus, recommend intervalSec ≥ 10s and set pollInterPollDelay ≥ 100ms to avoid bus congestion.
Q5: How to do both "local alarm" and "platform report" for the same sensor?
Two rules:
- Rule A: Poll trigger temperature > threshold → Fan + OLED (local alarm)
- Rule B: Timer trigger every 60s →
ACTION_SENSOR_READ(trigger collection) +reportAfterExec=true(report to MQTT)
Or chain in one rule's action array: collection → alarm → report, with reportAfterExec enabled.
Q6: Why aren't button events triggering?
Button events depend on GPIO_DIGITAL_INPUT_PULLUP / GPIO_DIGITAL_INPUT_PULLDOWN peripheral types (see supportsButtonEvent). Check:
- Is the peripheral type correct (type=12 or 13)?
- Debounce and double-click window: pressing too fast may be recognized as a single click instead of double-click (double-click window is 200ms).
- Does
triggerPeriphIdmatch the button peripheral ID (leave empty to match all buttons)?
Q7: What events can ACTION_TRIGGER_EVENT emit?
- System built-in event IDs: e.g.,
break_down/device_alarm/low_power/restart(see section 3.3). - Custom events: First create a
DEVICE_EVENT(type=60) peripheral in peripheral management; itsidcan then be used astargetPeriphId.
Q8: Does executing one rule affect other rules?
By default, async execution (independent FreeRTOS tasks) does not block each other. However, shared hardware (e.g., shared I²C bus, serial port) still needs to avoid concurrent contention. With many rules, prefer async; for short GPIO actions, consider sync (execMode=1) to reduce task creation overhead.
Q9: What is reportAfterExec?
After execution completes, the action execution results (including targetPeriphId, actualValue, success/failure reason) are reported to the platform via the protocolType preferred protocol. Enabled by default; if the rule only does local interlocking (e.g., local alarm), disable it to reduce upstream traffic.
Q10: How to debug rules?
- Enable serial logging (115200), look for
[PeriphExec]prefix. - Use the UI "Run Once" button to manually trigger once.
- Use
ACTION_TRIGGER_EVENTto emitdevice_alarmevents and observe whether the MQTT subscriber receives the corresponding topic. - Temporarily change
execModeto sync; the logs will show serial execution order, helping locate failure steps.
Related Documents
- Peripheral Configuration Guide — Peripheral types, pins, compile switches
- PeriphExec Module In-Depth — Implementation architecture, task scheduling, source code analysis
- OLED Usage Guide — LCD/OLED hardware wiring and U8g2 fonts
- Modbus Usage Guide — Modbus RTU/TCP slave configuration
- Script Engine Guide — Command sequence scripts for
ACTION_SCRIPTactions
