Compare commits

..

3 commits
main ... tyler

Author SHA1 Message Date
Tyler Cooper
6622b198d5 compare text changes 2025-08-25 15:27:09 -05:00
Tyler Cooper
abb1e0f561 Update inner submodule 2025-08-25 15:24:06 -05:00
Tyler Cooper
4b242cdd49 docs: compare_and_multiline_text 2025-08-25 15:06:30 -05:00
4 changed files with 650 additions and 45 deletions

View file

@ -1,67 +1,230 @@
/** @type {import('#types').BlockDefinitionRaw} */
export default {
type: 'text_compare',
bytecodeKey: 'textCompare',
name: "Compare Text",
colour: 180,
inputsInline: true,
primaryCategory: "Logic",
description: "Compare any two pieces of text or data to build conditional logic in your Actions. Perfect for creating if/then statements like 'if device status equals online', 'if user name is not guest', or 'if error message contains timeout'. Works with feed values, variables, user input, or any text-based data.",
name: "Text Compare",
colour: 160,
description: `Compare two text values using different comparison operations. Perfect for conditional logic, filtering data, validating user input, or creating smart automation rules based on text content matching, differences, or substring detection.
## What is Text Compare?
The Text Compare block evaluates two text inputs using a specified comparison operator and returns true or false. This enables you to build conditional logic based on text content, whether checking for exact matches, detecting differences, or finding substrings within larger text.
## How It Works
The block performs three types of text comparison operations:
- **Equals (=)** - Exact match comparison (case-sensitive)
- **Not Equals ()** - Different text detection
- **Includes** - Substring detection within text
## Comparison Operators
### Equals (=) - Exact Match
Returns true when both text values are exactly the same, including case sensitivity.
::: warning Case Sensitivity Alert
Text comparison is case-sensitive! "Hello" is NOT equal to "hello"
:::
**Examples:**
- "hello" = "hello" **true**
- "Hello" = "hello" **false** (case-sensitive)
- "test123" = "test123" **true**
- " test " = "test" **false** (whitespace matters)
**Common Uses:**
- Check device status: \`device_status = "online"\`
- Validate user role: \`user_role = "admin"\`
- Confirm completion: \`task_status = "completed"\`
### Not Equals () - Different Values
Returns true when text values are different in any way.
**Examples:**
- "hello" "world" **true**
- "same" "same" **false**
- "Test" "test" **true** (case-sensitive)
**Common Uses:**
- Detect changes: \`current_status ≠ previous_status\`
- 🚫 Block guest users: \`username ≠ "guest"\`
- 📝 Validate required fields: \`input_field ≠ ""\`
### Includes - Substring Detection
Returns true when the left text contains the right text as a substring.
::: tip Perfect for Keyword Searching
Use includes to search for keywords within longer text like error messages, logs, or user input
:::
**Examples:**
- "hello world" includes "world" **true**
- "temperature alert" includes "temp" **true**
- "test" includes "testing" **false** (left must contain right)
**Common Uses:**
- 🔍 Find errors: \`error_log includes "timeout"\`
- 📧 Email filtering: \`email_address includes "@company.com"\`
- 🎯 Command parsing: \`voice_command includes "lights"\`
## Practical Examples
::: details 🏠 Smart Home Examples
### Door & Security
~~~javascript
// Check if door is locked
door_status = "locked" Turn off porch light
// Alert if door left open
door_status "closed" Send notification
// Security monitoring
security_log includes "breach" Trigger alarm
~~~
### Temperature & Climate
~~~javascript
// AC control
room_temp = "hot" Turn on air conditioning
// Sensor errors
temp_reading includes "error" Send maintenance alert
// Room occupancy
bedroom_status "occupied" Reduce heating
~~~
:::
::: details 🔧 System Monitoring Examples
### Error Detection
~~~javascript
// System health
system_status "healthy" Send alert
error_message includes "critical" Immediate notification
// Performance monitoring
response_time includes "slow" Log performance issue
~~~
### Device Management
~~~javascript
// Connectivity checks
device_ping "success" Mark device offline
connection_type = "ethernet" Use high-speed settings
// Battery monitoring
battery_level includes "low" Send low battery warning
~~~
:::
## Common Issues & Solutions
::: details 🔤 Case Sensitivity Problems
::: danger Most Common Issue
"Online" "online" - Case matters in all comparisons!
:::
::: details Whitespace Issues
**Hidden spaces cause comparison failures:**
| What You See | Actual Value | Result |
|--------------|--------------|--------|
| "active" | "active " | Won't match "active" |
| "online" | " online" | Won't match "online" |
**Solutions:**
- Be aware extra spaces break matches
- Check for leading/trailing spaces in your data
- Clean data at the source when possible
:::
::: details 🔢 Text vs Numbers
::: warning Important
This block compares TEXT, not numbers! "10" vs "9" gives unexpected results
:::
## Best Practices
1. **🎯 Be Specific** - Use exact expected values when possible
2. **📝 Test Your Data** - Verify actual format of values before comparing
3. **🔤 Watch Case** - Remember comparisons are case-sensitive
4. ** Check Spaces** - Extra whitespace will break matches
5. **📖 Document Formats** - Note expected case/format in comments
## Quick Reference
### When to Use Each Operator
| Operator | Use When | Example |
|----------|----------|---------|
| **Equals (=)** | Need exact match | \`status = "online"\` |
| **Not Equals ()** | Need to detect difference | \`role ≠ "guest"\` |
| **Includes** | Search within text | \`message includes "error"\` |
### Related Blocks
- **Number Compare** - For numeric comparisons (>, <, >=, <=)
- **Logic AND/OR** - Combine multiple text comparisons
- **IF/Then** - Use comparison results to control flow`,
connections: {
mode: "value",
output: "expression",
output: ["expression", "boolean"]
},
template: `%A %OP %B`,
inputs: {
A: {
description: "The first value to compare (left side). Can be feed data, variable content, user input, or any text. Numbers and other data types will be automatically converted to text for comparison.",
check: "expression",
shadow: 'io_text'
description: "Left text value to compare",
types: ["expression", "string"],
shadow: "io_text"
},
B: {
description: "The second value to compare (right side). Can be literal text like 'online', variable content, feed values, or any data you want to compare against the first input. Also automatically converted to text.",
check: "expression",
shadow: 'io_text'
},
description: "Right text value to compare",
types: ["expression", "string"],
shadow: "io_text"
}
},
template: "%A %OP %B",
fields: {
OP: {
description: "Choose how to compare the two text inputs:",
options: [
['=', 'EQ', "Exact match: Returns true only if both inputs are identical (e.g., 'online' = 'online' is true, but 'Online' = 'online' is false due to case sensitivity)."],
['\u2260', 'NEQ', "Not equal: Returns true if the inputs are different in any way (e.g., useful for 'if status is not offline' or 'if username is not empty' conditions)."],
['includes', 'INC', "Contains: Returns true if the first input contains the second input anywhere within it (e.g., 'sensor error timeout' includes 'error' would be true)."],
['=', 'EQ'],
['\u2260', 'NEQ'],
['includes', 'INC']
]
}
},
generators: {
json: (block, generator) => {
const
comparator = block.getFieldValue('OP'),
leftExp = generator.valueToCode(block, 'A', 0) || null,
rightExp = generator.valueToCode(block, 'B', 0) || null,
blockPayload = JSON.stringify({
textCompare: {
left: JSON.parse(leftExp),
comparator: comparator?.toLowerCase() || null,
right: JSON.parse(rightExp),
},
})
return [ blockPayload, 0 ]
const comparator = block.getFieldValue('OP')
const leftExp = generator.valueToCode(block, 'A', 0)
const rightExp = generator.valueToCode(block, 'B', 0)
const blockPayload = {
textCompare: {
left: leftExp ? JSON.parse(leftExp) : null,
comparator: comparator?.toLowerCase() || null,
right: rightExp ? JSON.parse(rightExp) : null,
},
}
return [JSON.stringify(blockPayload), 0]
}
},
regenerators: {
json: (blockObject, helpers) => {
const
{ comparator, left, right } = blockObject.textCompare,
fields = {
OP: comparator?.toUpperCase()
},
inputs = {
A: helpers.expressionToBlock(left, { shadow: "io_text" }),
B: helpers.expressionToBlock(right, { shadow: "io_text" }),
}
const { comparator, left, right } = blockObject.textCompare
const fields = {
OP: comparator?.toUpperCase() || 'EQ'
}
const inputs = {
A: helpers.expressionToBlock(left, { shadow: "io_text" }),
B: helpers.expressionToBlock(right, { shadow: "io_text" }),
}
return { type: 'text_compare', fields, inputs }
}
}
}
}

View file

@ -3,7 +3,449 @@ export default {
type: 'io_text_multiline',
name: "Multiline Text",
colour: 180,
description: "Create formatted text content with multiple lines, paragraphs, and line breaks. Perfect for composing detailed email messages, creating formatted reports with sensor data, writing multi-paragraph notifications, or building structured text content that needs proper formatting and readability across multiple lines.",
description: `
Create formatted text content with multiple lines, paragraphs, and line breaks. Perfect for composing detailed email messages, creating formatted reports with sensor data, writing multi-paragraph notifications, or building structured text content that needs proper formatting and readability across multiple lines.
## What is Multiline Text?
The Multiline Text block lets you create text with proper formatting - line breaks, paragraphs, and structured content. Unlike single-line text blocks, this preserves your formatting exactly as you type it, making it ideal for emails, reports, logs, or any content that needs to span multiple lines with preserved structure.
## How It Works
::: info
Type your text with natural line breaks Formatting is preserved Output maintains structure
Press **Enter/Return** to create new lines. All spacing and line breaks are kept exactly as entered.
:::
The block captures text exactly as formatted:
- **Line breaks** are preserved (\\n characters)
- **Blank lines** create paragraph separation
- **Indentation** and spacing are maintained
- **Special characters** are handled properly
## Basic Examples
### Simple Multi-Line Message
**Input:**
\`\`\`
Hello there!
This is line two.
This is line three.
\`\`\`
**Output:**
\`\`\`
Hello there!
This is line two.
This is line three.
\`\`\`
### Paragraph Formatting
**Input:**
\`\`\`
First paragraph here.
Second paragraph with a blank line above.
Third paragraph for emphasis.
\`\`\`
**Output maintains the exact spacing and blank lines**
## IoT Use Cases
### 📧 Email Templates
**Device Alert Email:**
\`\`\`
Subject: Temperature Alert - Immediate Attention Required
Dear {{ user.name }},
We've detected an abnormal temperature reading from your sensor:
Location: {{ feeds['sensors.location'].name }}
Current Temperature: {{ feeds['sensors.temp'].value }}°F
Threshold: {{ vars.temp_threshold }}°F
Time: {{ feeds['sensors.temp'].updated_at }}
Please check your system immediately.
Best regards,
IoT Monitoring System
\`\`\`
**Welcome Email:**
\`\`\`
Welcome to Smart Home Monitor!
Hi {{ user.name }},
Your account has been successfully created.
Here's what you can do next:
1. Add your first device
2. Set up notifications
3. Create automation rules
Need help? Reply to this email or visit our support center.
Happy monitoring!
The Smart Home Team
\`\`\`
### 📊 Formatted Reports
**Daily System Report:**
\`\`\`
====================================
DAILY SYSTEM REPORT
Date: {{ vars.report_date }}
====================================
SENSOR STATUS:
--------------
Temperature Sensors: {{ vars.temp_sensor_count }} active
Motion Detectors: {{ vars.motion_count }} active
Door Sensors: {{ vars.door_count }} active
ALERTS TODAY:
-------------
Critical: {{ vars.critical_alerts }}
Warning: {{ vars.warning_alerts }}
Info: {{ vars.info_alerts }}
SYSTEM HEALTH:
--------------
Uptime: {{ vars.uptime }}
Battery Average: {{ vars.battery_avg }}%
Network Status: {{ vars.network_status }}
====================================
End of Report
\`\`\`
### 🔔 Detailed Notifications
**Multi-Event Alert:**
\`\`\`
SECURITY ALERT - Multiple Events Detected
Time: {{ vars.alert_time }}
The following events occurred within 5 minutes:
Front door opened
Motion detected in living room
Back door opened
Garage door activated
This unusual pattern has triggered a security alert.
All cameras are now recording.
Tap here to view live feed or dismiss if authorized.
\`\`\`
### 📝 Log Entries
**System Log Format:**
\`\`\`
[{{ vars.timestamp }}] SYSTEM START
[{{ vars.timestamp }}] Loading configuration...
[{{ vars.timestamp }}] Configuration loaded successfully
[{{ vars.timestamp }}] Connecting to sensors...
[{{ vars.timestamp }}] Connected: Temperature Sensor 1
[{{ vars.timestamp }}] Connected: Motion Detector A
[{{ vars.timestamp }}] All systems operational
=== BEGIN MONITORING ===
\`\`\`
### 📋 Instructions & Procedures
**Maintenance Instructions:**
\`\`\`
MONTHLY MAINTENANCE CHECKLIST
Please complete the following tasks:
SENSORS:
1. Clean sensor surfaces with soft cloth
2. Check mounting brackets for stability
3. Verify LED indicators are functioning
BATTERIES:
1. Test all battery levels
2. Replace if below 20%
3. Clean battery contacts
CONNECTIVITY:
1. Test wireless signal strength
2. Restart hub if needed
3. Update firmware if available
Sign off when complete: ___________
Date: ___________
\`\`\`
## Advanced Patterns
::: details ASCII Art and Diagrams
Create visual representations using ASCII characters:
\`\`\`
System Architecture:
[Sensors]
|
v
[IoT Hub]
|
+----+----+
| |
[Cloud] [Local]
| |
[Mobile] [Alert]
\`\`\`
**Status Dashboard:**
\`\`\`
+------------------+------------------+
| Temperature | Humidity |
| 72.5°F | 45% |
| | |
+------------------+------------------+
| Motion | Door |
| No Motion | Closed |
| | |
+------------------+------------------+
\`\`\`
:::
::: details Tables and Structured Data
Create aligned tables with consistent formatting:
\`\`\`
Sensor Readings - {{ vars.date }}
Name | Value | Status | Last Update
----------------|----------|--------|-------------
Living Room | 72.5°F | OK | 10:30 AM
Bedroom | 68.2°F | OK | 10:31 AM
Kitchen | 75.1°F | WARN | 10:29 AM
Garage | 62.0°F | OK | 10:32 AM
Legend: OK = Normal | WARN = Check | CRIT = Alert
\`\`\`
:::
::: details Dynamic Content with Variables
Combine static formatting with dynamic data:
\`\`\`
================================
{{ vars.company_name }}
{{ vars.report_type }} Report
================================
Generated: {{ vars.timestamp }}
Period: {{ vars.start_date }} to {{ vars.end_date }}
EXECUTIVE SUMMARY:
------------------
{{ vars.summary_text }}
KEY METRICS:
------------
Uptime: {{ vars.uptime_percent }}%
Alerts: {{ vars.total_alerts }}
Resolved: {{ vars.resolved_count }}
RECOMMENDATIONS:
----------------
{{ vars.recommendations }}
Next Review: {{ vars.next_review_date }}
\`\`\`
:::
::: details Message Templates with Placeholders
Create reusable templates with variable insertion points:
\`\`\`
STANDARD ALERT TEMPLATE
=======================
Priority: [PRIORITY_LEVEL]
Time: [TIMESTAMP]
Device: [DEVICE_NAME]
Alert Details:
[ALERT_MESSAGE]
Current Value: [CURRENT_VALUE]
Normal Range: [MIN_VALUE] - [MAX_VALUE]
Suggested Actions:
[ACTION_LIST]
This is an automated message.
To change alert settings, visit [SETTINGS_URL]
\`\`\`
:::
## Special Characters & Formatting
::: details Line Break Patterns
Different ways to create visual separation:
\`\`\`
Single line break (one Enter):
Line 1
Line 2
Double line break (two Enters):
Paragraph 1
Paragraph 2
Horizontal rules:
==================
------------------
******************
##################
\`\`\`
:::
::: details Special Characters
Common special characters in IoT messages:
\`\`\`
Temperature: 72.5°F / 22.5°C
Humidity: 45% ± 2%
Status: OK | Failed | Warning
Arrows: Up Down Right Left
Bullets:
Box Drawing:
Math: × ÷
\`\`\`
:::
::: details Indentation and Alignment
Control text alignment and hierarchy:
\`\`\`
Main Category
Sub-item 1
Detail A
Detail B
Sub-item 2
Detail C
Detail D
Main Category 2
Different structure here
\`\`\`
:::
## Working with Other Blocks
::: details Multiline Text + Text Template
Use Multiline Text for the structure, then enhance with Text Template for variables:
1. Create base structure in Multiline Text
2. Store in variable
3. Process with Text Template for dynamic values
:::
::: details Multiline Text + Send Email
Perfect combination for email automation:
1. Compose message in Multiline Text
2. Include variable placeholders
3. Connect to Send Email block
4. Variables are replaced at send time
:::
::: details Multiline Text + File Write
Create formatted logs and reports:
1. Build report structure in Multiline Text
2. Add timestamp and data
3. Write to file with proper formatting
4. Maintains all line breaks and structure
:::
## Troubleshooting
::: details Problem: Line breaks not showing
**Solution:**
- Ensure consuming blocks preserve \\n characters
- Some displays may need HTML breaks (<br>)
- Check if receiving system supports multiline
:::
::: details Problem: Text appears as single line
**Solution:**
- Verify the receiving system handles multiline
- May need to convert \\n to system-specific breaks
- Check encoding settings
:::
::: details Problem: Special characters not displaying
**Solution:**
- Check character encoding (UTF-8 recommended)
- Some systems may need HTML entities
- Test with basic ASCII first
:::
::: details Problem: Indentation lost
**Solution:**
- Use spaces instead of tabs
- Some systems strip leading whitespace
- Consider using non-breaking spaces
:::
## Quick Reference
::: details Common Formatting Patterns
| Pattern | Usage | Example |
|---------|-------|---------|
| Single line break | Separate lines | Line 1\\nLine 2 |
| Double line break | Paragraphs | Para 1\\n\\nPara 2 |
| Horizontal rule | Section divider | =============== |
| Indentation | Hierarchy | ····Sub-item |
| Bullet points | Lists | Item 1 |
| Headers | Section titles | SECTION TITLE |
| Box drawing | Tables/borders | |
:::
::: details When to Use Multiline vs Single Line
**Use Multiline Text when:**
- Creating emails or messages
- Building formatted reports
- Writing documentation or instructions
- Composing notifications with structure
- Creating ASCII art or diagrams
**Use Single Line Text when:**
- Simple labels or titles
- Short status messages
- Single data points
- URL or path values
:::
::: details Related Blocks
- **Text Template** - Add dynamic variables to your multiline content
- **Join Text** - Combine multiple text pieces
- **Send Email** - Use multiline text as email body
- **Write File** - Save formatted text to files
- **Display/Log** - Output formatted text to displays or logs
:::
`,
connections: {
mode: "value",
output: [ "expression", "string" ],
@ -11,7 +453,7 @@ export default {
template: "¶ %TEXT",
fields: {
TEXT: {
description: "Enter your multi-line text content here. Use Enter/Return to create new lines and paragraphs. Perfect for email templates ('Dear User,\\n\\nYour temperature reading is...\\n\\nBest regards'), formatted reports, detailed notifications, or any text that needs structure and readability.",
description: "Enter your multi-line text content here. Use Enter/Return to create new lines and paragraphs. Perfect for email templates ('Dear User,\\n\\nYour temperature reading is...\\n\\nBest regards'), formatted reports, detailed notifications, or any text that needs structure and readability. All formatting, spacing, and line breaks are preserved exactly as entered.",
multiline_text: ''
}
},
@ -21,4 +463,4 @@ export default {
return [ JSON.stringify(text), 0 ]
}
}
}
}

1
io-actions Submodule

@ -0,0 +1 @@
Subproject commit f68c52fc4f82ac34c152d2df8572afb244e98359

View file

@ -194,8 +194,7 @@ BlockDefinition.parseRawDefinition = function(rawBlockDefinition, definitionPath
// take the first line of the description
// blockDef.tooltip = blockDef.description.split("\n")[0]
// take the first sentence of the description
blockDef.tooltip = blockDef.description.split(/\.(\s|$)/)[0]
if(!blockDef.tooltip.endsWith("?")) { blockDef.tooltip += "." }
blockDef.tooltip = blockDef.description.split(/\.(\s|$)/)[0] + "."
blockDef.disabled = !!rawBlockDefinition.disabled
blockDef.connections = rawBlockDefinition.connections
blockDef.template = rawBlockDefinition.template