-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsimple-python.lotnb
More file actions
142 lines (142 loc) · 27.9 KB
/
simple-python.lotnb
File metadata and controls
142 lines (142 loc) · 27.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
[
{
"kind": 1,
"language": "markdown",
"value": "# Simple Python - Adding Programming Power\n\n[⬅️ Previous: Database Routes](../04-routes/database-routes.lotnb) | [🏠 Back to Index](../index.lotnb) | [➡️ Next: Advanced Python](./advanced-python.lotnb)\n\n---\n\n<details>\n<summary><strong>Navigation Menu</strong></summary>\n\n| Section | Tutorials |\n|---------|----------|\n| **Setup** | [Environment Setup](../00-setup/verify-environment.lotnb) |\n| **Basics** | [Timed Actions](../01-basics/timed-actions.lotnb) \\| [Topic Actions](../01-basics/topic-actions.lotnb) |\n| **Logic** | [Conditional Logic](../02-logic/conditional-logic.lotnb) |\n| **Models** | [Basic Models](../03-models/basic-models.lotnb) \\| [Action Models](../03-models/action-models.lotnb) \\| [Inheritance](../03-models/model-inheritance.lotnb) |\n| **Routes** | [MQTT Bridge](../04-routes/mqtt-bridge.lotnb) \\| [Database](../04-routes/database-routes.lotnb) |\n| **Python** | [Simple](./simple-python.lotnb) \\| [Advanced](./advanced-python.lotnb) |\n\n</details>\n\n---\n\n> **CAUTION - Free Tier Resource Limits**\n>\n> The free version of Coreflux has resource limits:\n> - **Routes**: 2 maximum\n> - **Actions**: 12 maximum\n> - **Models**: 40 maximum\n>\n> Delete unused resources before creating new ones during exercises.\n\n---\n\n## Learning Objectives\n\nIn this tutorial, you will learn:\n- How to integrate Python scripts with LoT actions\n- The `CALL PYTHON` syntax and parameter passing\n- Creating Python functions for LoT integration\n- Handling return values and JSON data\n- Error handling in Python scripts\n- When to use Python vs pure LoT logic\n\n---\n\n## 📖 Introduction\n\n**Python Integration** extends LoT's capabilities with full programming language features:\n- Complex calculations and algorithms\n- External library integration\n- File operations and data processing\n- Machine learning and AI integration\n- Advanced string manipulation and parsing\n\n### Real-World Applications\n- **Data Analysis**: Statistical calculations on sensor data\n- **Image Processing**: Analyze camera feeds with computer vision\n- **Machine Learning**: Predictive maintenance algorithms\n- **External APIs**: Complex API interactions and data transformation\n\n---\n\n## 🧠 Core Concepts\n\n### CALL PYTHON Syntax\n\n```lot\nCALL PYTHON \"ScriptName.function_name\"\n WITH (parameter1, parameter2, ...)\n RETURN AS {variable_name}\n```\n\n### Python Script Structure\n\n```python\n# Script Name: ScriptName\ndef function_name(param1, param2):\n # Your Python code here\n return result\n```\n\n### Parameter Passing\n\n- **Single Parameter**: `WITH (PAYLOAD)`\n- **Multiple Parameters**: `WITH (param1, param2, param3)`\n- **Mixed Types**: `WITH (PAYLOAD, \"string\", 123, TRUE)`\n\n### Return Value Handling\n\n- **Simple Values**: Return strings, numbers, booleans\n- **JSON Objects**: Return dictionaries for structured data\n- **Error Handling**: Return error indicators or None\n\n---\n\n## 🛠️ Hands-On Examples\n\n### Example 1: Simple Math Calculator\n\nLet's start with basic Python functions:"
},
{
"kind": 2,
"language": "python",
"value": "# Script Name: MathCalculator\r\ndef add_numbers(a, b):\r\n \"\"\"Add two numbers and return the result\"\"\"\r\n try:\r\n result = float(a) + float(b)\r\n return result\r\n except (ValueError, TypeError):\r\n return 0\r\n\r\ndef calculate_percentage(value, total):\r\n \"\"\"Calculate percentage with error handling\"\"\"\r\n try:\r\n if float(total) == 0:\r\n return 0\r\n percentage = (float(value) / float(total)) * 100\r\n return round(percentage, 2)\r\n except (ValueError, TypeError, ZeroDivisionError):\r\n return 0\r\n\r\ndef format_temperature(celsius):\r\n \"\"\"Convert Celsius to Fahrenheit and format nicely\"\"\"\r\n try:\r\n celsius_val = float(celsius)\r\n fahrenheit = (celsius_val * 9/5) + 32\r\n return f\"{celsius_val}°C ({fahrenheit:.1f}°F)\"\r\n except (ValueError, TypeError):\r\n return \"Invalid temperature\""
},
{
"kind": 2,
"language": "lot",
"value": "DEFINE ACTION SimpleMathProcessor\r\nON TOPIC \"math/+/calculate\" DO\r\n SET \"operation\" WITH TOPIC POSITION 2\r\n \r\n IF {operation} EQUALS \"add\" THEN\r\n // Expect payload like \"5,3\" for adding 5 + 3\r\n SET \"numbers\" WITH PAYLOAD\r\n CALL PYTHON \"MathCalculator.add_numbers\"\r\n WITH (5, 3)\r\n RETURN AS {result}\r\n PUBLISH TOPIC \"math/add/result\" WITH {result}\r\n \r\n ELSE IF {operation} EQUALS \"percentage\" THEN\r\n // Calculate percentage: value out of total\r\n CALL PYTHON \"MathCalculator.calculate_percentage\"\r\n WITH (GET TOPIC \"math/current/value\", GET TOPIC \"math/current/total\")\r\n RETURN AS {percentage}\r\n PUBLISH TOPIC \"math/percentage/result\" WITH {percentage}\r\n \r\n ELSE IF {operation} EQUALS \"temperature\" THEN\r\n // Format temperature with conversion\r\n CALL PYTHON \"MathCalculator.format_temperature\"\r\n WITH (PAYLOAD)\r\n RETURN AS {formatted_temp}\r\n PUBLISH TOPIC \"math/temperature/formatted\" WITH {formatted_temp}"
},
{
"kind": 1,
"language": "markdown",
"value": "**What this does:**\n- Defines simple Python functions for common calculations\n- Calls different Python functions based on topic structure\n- Handles parameters from both payload and stored topics\n- Includes error handling in Python functions\n- Demonstrates basic Python-LoT integration\n\n**Test it:**\n```\nPublish to: math/temperature/calculate\nPayload: 25\nResult in math/temperature/formatted: \"25°C (77.0°F)\"\n```\n\n---\n\n### Example 2: String Processing Functions\n\nLet's create Python functions for text processing:"
},
{
"kind": 2,
"language": "python",
"value": "# Script Name: TextProcessor\r\ndef clean_sensor_data(raw_data):\r\n \"\"\"Clean and validate sensor data string\"\"\"\r\n try:\r\n # Remove whitespace and convert to uppercase\r\n cleaned = str(raw_data).strip().upper()\r\n \r\n # Basic validation\r\n if len(cleaned) == 0:\r\n return \"INVALID_DATA\"\r\n \r\n # Remove special characters except numbers and letters\r\n import re\r\n cleaned = re.sub(r'[^A-Z0-9._-]', '', cleaned)\r\n \r\n return cleaned\r\n except Exception as e:\r\n return f\"ERROR: {str(e)}\"\r\n\r\ndef parse_equipment_code(equipment_string):\r\n \"\"\"Parse equipment code and return structured information\"\"\"\r\n try:\r\n # Expected format: \"PUMP_001_LINE_A\"\r\n parts = str(equipment_string).split('_')\r\n \r\n if len(parts) >= 4:\r\n return {\r\n \"equipment_type\": parts[0],\r\n \"equipment_number\": parts[1],\r\n \"line_id\": parts[2],\r\n \"section\": parts[3],\r\n \"full_code\": equipment_string\r\n }\r\n else:\r\n return {\"error\": \"Invalid equipment code format\"}\r\n except Exception as e:\r\n return {\"error\": str(e)}\r\n\r\ndef generate_report_summary(data_json):\r\n \"\"\"Generate a text summary from JSON data\"\"\"\r\n try:\r\n import json\r\n data = json.loads(data_json) if isinstance(data_json, str) else data_json\r\n \r\n summary_parts = []\r\n \r\n if 'production_count' in data:\r\n summary_parts.append(f\"Produced: {data['production_count']} units\")\r\n \r\n if 'efficiency' in data:\r\n summary_parts.append(f\"Efficiency: {data['efficiency']}%\")\r\n \r\n if 'quality_rate' in data:\r\n summary_parts.append(f\"Quality: {data['quality_rate']}%\")\r\n \r\n if 'operator' in data:\r\n summary_parts.append(f\"Operator: {data['operator']}\")\r\n \r\n return \" | \".join(summary_parts) if summary_parts else \"No data available\"\r\n \r\n except Exception as e:\r\n return f\"Summary generation error: {str(e)}\""
},
{
"kind": 2,
"language": "lot",
"value": "DEFINE ACTION TextProcessingDemo\r\nON TOPIC \"text/+/process\" DO\r\n SET \"operation\" WITH TOPIC POSITION 2\r\n \r\n IF {operation} EQUALS \"clean\" THEN\r\n // Clean sensor data\r\n CALL PYTHON \"TextProcessor.clean_sensor_data\"\r\n WITH (PAYLOAD)\r\n RETURN AS {cleaned_data}\r\n PUBLISH TOPIC \"text/clean/result\" WITH {cleaned_data}\r\n \r\n ELSE IF {operation} EQUALS \"parse\" THEN\r\n // Parse equipment code\r\n CALL PYTHON \"TextProcessor.parse_equipment_code\"\r\n WITH (PAYLOAD)\r\n RETURN AS {parsed_info}\r\n PUBLISH TOPIC \"text/parse/result\" WITH {parsed_info}\r\n \r\n ELSE IF {operation} EQUALS \"summary\" THEN\r\n // Generate report summary\r\n CALL PYTHON \"TextProcessor.generate_report_summary\"\r\n WITH (PAYLOAD)\r\n RETURN AS {summary}\r\n PUBLISH TOPIC \"text/summary/result\" WITH {summary}"
},
{
"kind": 1,
"language": "markdown",
"value": "**What this does:**\n- Provides text cleaning and validation functions\n- Parses structured equipment codes into components\n- Generates human-readable summaries from JSON data\n- Includes comprehensive error handling\n- Demonstrates practical text processing use cases\n\n**Test it:**\n```\nPublish to: text/parse/process\nPayload: \"PUMP_001_LINE_A\"\nResult in text/parse/result:\n{\n \"equipment_type\": \"PUMP\",\n \"equipment_number\": \"001\",\n \"line_id\": \"LINE\",\n \"section\": \"A\",\n \"full_code\": \"PUMP_001_LINE_A\"\n}\n```\n\n---\n\n### Example 3: Data Validation Functions\n\nLet's create Python functions for data validation:"
},
{
"kind": 2,
"language": "python",
"value": "# Script Name: DataValidator\r\ndef validate_sensor_reading(value, min_val, max_val):\r\n \"\"\"Validate sensor reading against acceptable range\"\"\"\r\n try:\r\n reading = float(value)\r\n min_limit = float(min_val)\r\n max_limit = float(max_val)\r\n \r\n if reading < min_limit:\r\n return {\r\n \"valid\": False,\r\n \"reason\": \"Below minimum\",\r\n \"value\": reading,\r\n \"min_limit\": min_limit,\r\n \"max_limit\": max_limit\r\n }\r\n elif reading > max_limit:\r\n return {\r\n \"valid\": False,\r\n \"reason\": \"Above maximum\",\r\n \"value\": reading,\r\n \"min_limit\": min_limit,\r\n \"max_limit\": max_limit\r\n }\r\n else:\r\n return {\r\n \"valid\": True,\r\n \"reason\": \"Within range\",\r\n \"value\": reading,\r\n \"min_limit\": min_limit,\r\n \"max_limit\": max_limit\r\n }\r\n except (ValueError, TypeError) as e:\r\n return {\r\n \"valid\": False,\r\n \"reason\": f\"Invalid data: {str(e)}\",\r\n \"value\": value\r\n }\r\n\r\ndef check_equipment_id_format(equipment_id):\r\n \"\"\"Validate equipment ID format\"\"\"\r\n import re\r\n \r\n try:\r\n # Expected format: 3 letters + 3 digits (e.g., PMP001, CNV002)\r\n pattern = r'^[A-Z]{3}[0-9]{3}$'\r\n \r\n if re.match(pattern, str(equipment_id)):\r\n return {\r\n \"valid\": True,\r\n \"format\": \"Standard\",\r\n \"type_code\": equipment_id[:3],\r\n \"number\": equipment_id[3:]\r\n }\r\n else:\r\n return {\r\n \"valid\": False,\r\n \"format\": \"Invalid\",\r\n \"expected\": \"3 letters + 3 digits (e.g., PMP001)\"\r\n }\r\n except Exception as e:\r\n return {\"valid\": False, \"error\": str(e)}"
},
{
"kind": 2,
"language": "lot",
"value": "DEFINE ACTION DataValidationProcessor\r\nON TOPIC \"validation/+/check\" DO\r\n SET \"validation_type\" WITH TOPIC POSITION 2\r\n \r\n IF {validation_type} EQUALS \"sensor\" THEN\r\n // Validate sensor reading\r\n CALL PYTHON \"DataValidator.validate_sensor_reading\"\r\n WITH (PAYLOAD, GET TOPIC \"validation/sensor/min\", GET TOPIC \"validation/sensor/max\")\r\n RETURN AS {validation_result}\r\n \r\n // Route based on validation result\r\n SET \"is_valid\" WITH (GET JSON \"valid\" IN {validation_result} AS BOOL)\r\n IF {is_valid} EQUALS TRUE THEN\r\n PUBLISH TOPIC \"validation/sensor/passed\" WITH {validation_result}\r\n PUBLISH TOPIC \"sensors/validated/reading\" WITH PAYLOAD\r\n ELSE\r\n PUBLISH TOPIC \"validation/sensor/failed\" WITH {validation_result}\r\n PUBLISH TOPIC \"alarms/validation/sensor\" WITH (GET JSON \"reason\" IN {validation_result} AS STRING)\r\n \r\n ELSE IF {validation_type} EQUALS \"equipment\" THEN\r\n // Validate equipment ID format\r\n CALL PYTHON \"DataValidator.check_equipment_id_format\"\r\n WITH (PAYLOAD)\r\n RETURN AS {format_check}\r\n \r\n SET \"format_valid\" WITH (GET JSON \"valid\" IN {format_check} AS BOOL)\r\n IF {format_valid} EQUALS TRUE THEN\r\n PUBLISH TOPIC \"validation/equipment/passed\" WITH {format_check}\r\n PUBLISH TOPIC \"equipment/validated/id\" WITH PAYLOAD\r\n ELSE\r\n PUBLISH TOPIC \"validation/equipment/failed\" WITH {format_check}\r\n PUBLISH TOPIC \"alarms/validation/equipment\" WITH \"Invalid equipment ID format: \" + PAYLOAD"
},
{
"kind": 1,
"language": "markdown",
"value": "**What this does:**\n- Validates sensor readings against acceptable ranges\n- Checks equipment ID format compliance\n- Routes data based on validation results\n- Creates alarms for invalid data\n- Demonstrates Python-based validation logic\n- Shows JSON data extraction from Python returns\n\n**Key Features:**\n- **Range Validation**: Check if sensor values are within acceptable limits\n- **Format Validation**: Ensure equipment IDs follow company standards\n- **Conditional Routing**: Valid data goes to validated topics, invalid to alarms\n- **Structured Returns**: Python returns detailed validation information\n\n**Test it:**\n```\nSet validation limits:\n validation/sensor/min: 0\n validation/sensor/max: 100\n\nPublish to: validation/sensor/check\nPayload: 75\nResult in validation/sensor/passed:\n{\n \"valid\": true,\n \"reason\": \"Within range\",\n \"value\": 75,\n \"min_limit\": 0,\n \"max_limit\": 100\n}\n```\n\n---\n\n### Example 4: Simple Data Transformation\n\nLet's create Python functions for data transformation:"
},
{
"kind": 2,
"language": "python",
"value": "# Script Name: DataTransformer\r\ndef convert_units(value, from_unit, to_unit):\r\n \"\"\"Convert between different units\"\"\"\r\n try:\r\n val = float(value)\r\n \r\n # Temperature conversions\r\n if from_unit == \"celsius\" and to_unit == \"fahrenheit\":\r\n return (val * 9/5) + 32\r\n elif from_unit == \"fahrenheit\" and to_unit == \"celsius\":\r\n return (val - 32) * 5/9\r\n \r\n # Pressure conversions\r\n elif from_unit == \"psi\" and to_unit == \"bar\":\r\n return val * 0.0689476\r\n elif from_unit == \"bar\" and to_unit == \"psi\":\r\n return val * 14.5038\r\n \r\n # Length conversions\r\n elif from_unit == \"mm\" and to_unit == \"inches\":\r\n return val * 0.0393701\r\n elif from_unit == \"inches\" and to_unit == \"mm\":\r\n return val * 25.4\r\n \r\n else:\r\n return val # No conversion needed or unknown units\r\n \r\n except (ValueError, TypeError):\r\n return 0\r\n\r\ndef create_equipment_summary(equipment_data):\r\n \"\"\"Create a summary string from equipment data\"\"\"\r\n try:\r\n # equipment_data expected as JSON string\r\n import json\r\n data = json.loads(equipment_data) if isinstance(equipment_data, str) else equipment_data\r\n \r\n summary_parts = []\r\n \r\n if 'name' in data:\r\n summary_parts.append(f\"Equipment: {data['name']}\")\r\n \r\n if 'status' in data:\r\n summary_parts.append(f\"Status: {data['status']}\")\r\n \r\n if 'runtime_hours' in data:\r\n summary_parts.append(f\"Runtime: {data['runtime_hours']}h\")\r\n \r\n if 'efficiency' in data:\r\n summary_parts.append(f\"Efficiency: {data['efficiency']}%\")\r\n \r\n return \" | \".join(summary_parts)\r\n \r\n except Exception as e:\r\n return f\"Summary error: {str(e)}\""
},
{
"kind": 2,
"language": "lot",
"value": "DEFINE ACTION DataTransformationProcessor\r\nON TOPIC \"transform/+/request\" DO\r\n SET \"transform_type\" WITH TOPIC POSITION 2\r\n \r\n IF {transform_type} EQUALS \"units\" THEN\r\n // Convert units using Python\r\n CALL PYTHON \"DataTransformer.convert_units\"\r\n WITH (PAYLOAD, GET TOPIC \"transform/units/from\", GET TOPIC \"transform/units/to\")\r\n RETURN AS {converted_value}\r\n PUBLISH TOPIC \"transform/units/result\" WITH {converted_value}\r\n PUBLISH TOPIC \"transform/units/original\" WITH PAYLOAD\r\n PUBLISH TOPIC \"transform/units/timestamp\" WITH TIMESTAMP \"UTC\"\r\n \r\n ELSE IF {transform_type} EQUALS \"summary\" THEN\r\n // Create equipment summary\r\n CALL PYTHON \"DataTransformer.create_equipment_summary\"\r\n WITH (PAYLOAD)\r\n RETURN AS {summary}\r\n PUBLISH TOPIC \"transform/summary/result\" WITH {summary}\r\n PUBLISH TOPIC \"transform/summary/generated_at\" WITH TIMESTAMP \"UTC\""
},
{
"kind": 1,
"language": "markdown",
"value": "**What this does:**\n- Provides unit conversion functions for common industrial units\n- Creates human-readable summaries from JSON data\n- Handles multiple unit types (temperature, pressure, length)\n- Includes comprehensive error handling\n- Demonstrates practical data transformation use cases\n\n**Test it:**\n```\nSet conversion parameters:\n transform/units/from: \"celsius\"\n transform/units/to: \"fahrenheit\"\n\nPublish to: transform/units/request\nPayload: 25\nResult in transform/units/result: 77\n```\n\n---\n\n### Example 5: Simple JSON Processing\n\nLet's work with JSON data in Python:"
},
{
"kind": 2,
"language": "python",
"value": "# Script Name: JSONProcessor\r\ndef extract_sensor_values(json_data):\r\n \"\"\"Extract specific values from sensor JSON\"\"\"\r\n try:\r\n import json\r\n data = json.loads(json_data) if isinstance(json_data, str) else json_data\r\n \r\n extracted = {\r\n \"temperature\": data.get(\"temperature\", 0),\r\n \"pressure\": data.get(\"pressure\", 0),\r\n \"flow_rate\": data.get(\"flow_rate\", 0),\r\n \"timestamp\": data.get(\"timestamp\", \"\"),\r\n \"sensor_count\": len([k for k in data.keys() if k not in ['timestamp', 'sensor_id']])\r\n }\r\n \r\n return json.dumps(extracted)\r\n \r\n except Exception as e:\r\n return json.dumps({\"error\": str(e)})\r\n\r\ndef calculate_averages(readings_json):\r\n \"\"\"Calculate averages from array of readings\"\"\"\r\n try:\r\n import json\r\n readings = json.loads(readings_json) if isinstance(readings_json, str) else readings_json\r\n \r\n if not isinstance(readings, list) or len(readings) == 0:\r\n return json.dumps({\"error\": \"No readings provided\"})\r\n \r\n # Calculate averages\r\n total = sum(readings)\r\n count = len(readings)\r\n average = total / count\r\n \r\n result = {\r\n \"average\": round(average, 2),\r\n \"total\": total,\r\n \"count\": count,\r\n \"min_value\": min(readings),\r\n \"max_value\": max(readings)\r\n }\r\n \r\n return json.dumps(result)\r\n \r\n except Exception as e:\r\n return json.dumps({\"error\": str(e)})"
},
{
"kind": 2,
"language": "lot",
"value": "DEFINE ACTION JSONProcessingDemo\r\nON TOPIC \"json/+/process\" DO\r\n SET \"operation\" WITH TOPIC POSITION 2\r\n \r\n IF {operation} EQUALS \"extract\" THEN\r\n // Extract sensor values from JSON\r\n CALL PYTHON \"JSONProcessor.extract_sensor_values\"\r\n WITH (PAYLOAD)\r\n RETURN AS {extracted_data}\r\n PUBLISH TOPIC \"json/extract/result\" WITH {extracted_data}\r\n \r\n ELSE IF {operation} EQUALS \"average\" THEN\r\n // Calculate averages from array\r\n CALL PYTHON \"JSONProcessor.calculate_averages\"\r\n WITH (PAYLOAD)\r\n RETURN AS {averages}\r\n PUBLISH TOPIC \"json/average/result\" WITH {averages}\r\n \r\n // Extract individual values for further processing\r\n PUBLISH TOPIC \"json/average/value\" WITH (GET JSON \"average\" IN {averages} AS DOUBLE)\r\n PUBLISH TOPIC \"json/average/count\" WITH (GET JSON \"count\" IN {averages} AS INT)"
},
{
"kind": 1,
"language": "markdown",
"value": "**What this does:**\r\n- Extracts specific values from complex JSON payloads\r\n- Calculates statistical measures (average, min, max) from arrays\r\n- Returns structured JSON results\r\n- Extracts individual values for LoT processing\r\n- Demonstrates JSON handling patterns\r\n\r\n**Test it:**\r\n```\r\nPublish to: json/average/process\r\nPayload: [10, 20, 30, 40, 50]\r\nResult in json/average/result:\r\n{\r\n \"average\": 30.0,\r\n \"total\": 150,\r\n \"count\": 5,\r\n \"min_value\": 10,\r\n \"max_value\": 50\r\n}\r\n```\r\n\r\n---\r\n\r\n## 🏋️ Exercises\r\n\r\n### Exercise 1: Simple Calculator\r\n**Task**: Create Python functions and LoT action for:\r\n- `multiply_numbers(a, b)` - multiply two numbers\r\n- `divide_numbers(a, b)` - divide with zero-check\r\n- Action that processes `calc/+/operation` and calls appropriate function"
},
{
"kind": 2,
"language": "python",
"value": "# Exercise 1: Write your Python functions here\n"
},
{
"kind": 2,
"language": "lot",
"value": "// Exercise 1: Write your LoT action here\n"
},
{
"kind": 1,
"language": "markdown",
"value": "### Exercise 2: Text Formatter\r\n**Task**: Create Python functions for text formatting:\r\n- `format_sensor_name(raw_name)` - clean and standardize sensor names\r\n- `create_alert_message(sensor, value, threshold)` - generate alert text\r\n- Action that processes formatting requests"
},
{
"kind": 2,
"language": "python",
"value": "# Exercise 2: Write your Python functions here\n"
},
{
"kind": 2,
"language": "lot",
"value": "// Exercise 2: Write your LoT action here\n"
},
{
"kind": 1,
"language": "markdown",
"value": "### Exercise 3: Data Quality Checker\r\n**Task**: Create a data quality system:\r\n- Python function to check data completeness, range validity, format compliance\r\n- Return quality score (0-100) and list of issues\r\n- LoT action that routes data based on quality score"
},
{
"kind": 2,
"language": "python",
"value": "# Exercise 3: Write your Python functions here\n"
},
{
"kind": 2,
"language": "lot",
"value": "// Exercise 3: Write your LoT action here\n"
},
{
"kind": 1,
"language": "markdown",
"value": "### Exercise 4: Simple Statistics Calculator\r\n**Task**: Create statistical functions:\r\n- Calculate mean, median, standard deviation from array of values\r\n- Detect outliers and anomalies\r\n- Generate statistical summary reports\r\n\r\n**Challenge**: Include trend analysis (increasing, decreasing, stable)."
},
{
"kind": 2,
"language": "python",
"value": "# Exercise 4: Write your Python functions here\n"
},
{
"kind": 2,
"language": "lot",
"value": "// Exercise 4: Write your LoT action here\n"
},
{
"kind": 1,
"language": "markdown",
"value": "\r\n\r\n---\r\n\r\n## 🎯 Checkpoint Questions\r\n\r\n1. **How do you pass multiple parameters to a Python function?**\r\n - Answer: Use `WITH (param1, param2, param3)` syntax\r\n\r\n2. **What should Python functions return for LoT integration?**\r\n - Answer: Simple values (string, number, boolean) or JSON-serializable dictionaries/lists\r\n\r\n3. **How do you extract values from JSON returned by Python?**\r\n - Answer: Use `GET JSON \"field_name\" IN {variable} AS TYPE`\r\n\r\n4. **When should you use Python instead of pure LoT logic?**\r\n - Answer: For complex calculations, string processing, external libraries, or advanced algorithms\r\n\r\n---\r\n\r\n## 📝 Summary\r\n\r\n### Key Concepts Learned\r\n✅ **CALL PYTHON** - Integrating Python functions with LoT actions \r\n✅ **Parameter Passing** - Sending data from LoT to Python \r\n✅ **Return Handling** - Processing Python function results \r\n✅ **Error Handling** - Robust error management in Python \r\n✅ **JSON Processing** - Working with structured data \r\n✅ **Data Validation** - Using Python for complex validation logic \r\n\r\n### Python Integration Patterns\r\n- **Calculations**: Mathematical operations beyond basic LoT math\r\n- **Validation**: Complex data validation and format checking\r\n- **Transformation**: Data format conversion and processing\r\n- **Text Processing**: String manipulation and parsing\r\n- **JSON Handling**: Complex JSON data extraction and manipulation\r\n### When to Use Python Or LoT? \r\n\r\n\r\n| Use Case | LoT Actions | Python Functions |\r\n|----------|-------------|------------------|\r\n| **Simple routing** | ✅ Fast, built-in | ❌ Overkill |\r\n| **Basic math** | ✅ Native support | ❌ Unnecessary |\r\n| **Complex calculations** | ❌ Limited | ✅ Full math libraries |\r\n| **String processing** | ❌ Basic only | ✅ Regex, formatting |\r\n| **External libraries** | ❌ Not supported | ✅ Full ecosystem |\r\n| **Data validation** | ❌ Simple checks only | ✅ Complex validation |\r\n\r\n### Advanced Python Features\r\n- External library integration (requests, pandas, numpy)\r\n- File operations and data persistence\r\n- Machine learning model integration\r\n- Image and signal processing\r\n\r\n### Performance Considerations\r\n- Function execution time impact\r\n- Memory usage with large data sets\r\n- Caching strategies for expensive operations\r\n- Asynchronous processing patterns\r\n\r\n\r\n### Next Steps\r\n- Practice creating simple Python functions\r\n- Experiment with different parameter types\r\n- Try JSON data processing\r\n- Move on to [Advanced Python](./advanced-python.lotnb) for complex integrations\r\n\r\n---\r\n\r\n## 🚀 Further Exploration\r\n\r\n### Advanced Python Features\r\n- External library integration (requests, pandas, numpy)\r\n- File operations and data persistence\r\n- Machine learning model integration\r\n- Image and signal processing\r\n\r\n### Performance Considerations\r\n- Function execution time impact\r\n- Memory usage with large data sets\r\n- Caching strategies for expensive operations\r\n- Asynchronous processing patterns\r\n\r\n### Error Handling Strategies\r\n- Graceful degradation on Python errors\r\n- Logging and debugging techniques\r\n- Timeout handling for long-running functions\r\n- Resource cleanup and management\r\n\r\n---\r\n\r\n**Ready for advanced Python integration? Continue with [🚀 Advanced Python](./advanced-python.lotnb)!**\r\n\r\n[⬅️ Previous: Database Routes](../04-routes/database-routes.lotnb) | [🏠 Back to Index](../index.lotnb) | [➡️ Next: Advanced Python](./advanced-python.lotnb)"
}
]