From 1a4afa199b5f541d90222f1958b1386b38cb05c6 Mon Sep 17 00:00:00 2001 From: Sasa Karanovic Date: Fri, 22 Oct 2021 00:24:05 -0400 Subject: [PATCH] Adding part 3 source files --- .../grafana_dashboard/dashboard.json | 632 ++++++++++++++++++ .../mysql/plantsystem.sql | 112 ++++ .../n8n/PlantSystem_-_Periodic_Watering.json | 319 +++++++++ .../n8n/PlantSystem_-_Read_Sensor_Data.json | 186 ++++++ .../n8n/PlantSystem_-_Water_All_Plants.json | 298 +++++++++ .../PlantSystem_-_Water_Specific_Plant.json | 208 ++++++ README.md | 11 +- 7 files changed, 1764 insertions(+), 2 deletions(-) create mode 100644 Part3_Web_and_Automation/grafana_dashboard/dashboard.json create mode 100644 Part3_Web_and_Automation/mysql/plantsystem.sql create mode 100644 Part3_Web_and_Automation/n8n/PlantSystem_-_Periodic_Watering.json create mode 100644 Part3_Web_and_Automation/n8n/PlantSystem_-_Read_Sensor_Data.json create mode 100644 Part3_Web_and_Automation/n8n/PlantSystem_-_Water_All_Plants.json create mode 100644 Part3_Web_and_Automation/n8n/PlantSystem_-_Water_Specific_Plant.json diff --git a/Part3_Web_and_Automation/grafana_dashboard/dashboard.json b/Part3_Web_and_Automation/grafana_dashboard/dashboard.json new file mode 100644 index 0000000..c8a0d7d --- /dev/null +++ b/Part3_Web_and_Automation/grafana_dashboard/dashboard.json @@ -0,0 +1,632 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 9, + "iteration": 1634868145960, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "MySQL - Plant System", + "description": "", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 24, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.5.4", + "pointradius": 2, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "sensorID", + "rawQuery": true, + "rawSql": "SELECT\r\n UNIX_TIMESTAMP(`insertTime`) AS `time`,\r\n `sensor_links`.`plantName` AS `metric`,\r\n `sensor_data`.`T` as `value` \r\nFROM `sensor_data`\r\nLEFT JOIN `sensor_links` ON\r\n`sensor_data`.`address` = `sensor_links`.`sensorAddress`\r\nWHERE $__timeFilter(`insertTime`)", + "refId": "Temperature", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "sensor_data", + "timeColumn": "timestamp", + "timeColumnType": "int", + "where": [ + { + "name": "$__unixEpochFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Temperature", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "transformations": [ + { + "id": "seriesToColumns", + "options": { + "byField": "Time" + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": { + "Cactus Large": 2, + "Cactus Small": 4, + "Palm Tree": 3, + "Pineapple": 1, + "Time": 0 + }, + "renameByName": {} + } + } + ], + "transparent": true, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:66", + "decimals": 1, + "format": "celsius", + "label": "", + "logBase": 1, + "max": "55", + "min": "20", + "show": true + }, + { + "$$hashKey": "object:67", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "MySQL - Plant System", + "description": "", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 11 + }, + "hiddenSeries": false, + "id": 3, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.5.4", + "pointradius": 2, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "sensorID", + "rawQuery": true, + "rawSql": "SELECT\r\n UNIX_TIMESTAMP(`insertTime`) AS `time`,\r\n `sensor_links`.`plantName` AS metric,\r\n (4095-`sensor_data`.`M`) AS `value`\r\nFROM `sensor_data`\r\nLEFT JOIN `sensor_links` ON\r\n`sensor_data`.`address` = `sensor_links`.`sensorAddress`\r\nWHERE $__timeFilter(`insertTime`)", + "refId": "Soil Moisture", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "sensor_data", + "timeColumn": "timestamp", + "timeColumnType": "int", + "where": [ + { + "name": "$__unixEpochFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Soil Moisture", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "transformations": [ + { + "id": "seriesToColumns", + "options": { + "byField": "Time" + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": { + "Cactus Large": 2, + "Cactus Small": 4, + "Palm Tree": 3, + "Pineapple": 1, + "Time": 0 + }, + "renameByName": {} + } + } + ], + "transparent": true, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:66", + "decimals": 0, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:67", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "MySQL - Plant System", + "description": "", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 21 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.5.4", + "pointradius": 2, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "sensorID", + "rawQuery": true, + "rawSql": "SELECT\r\n UNIX_TIMESTAMP(`insertTime`) AS `time`,\r\n `sensor_links`.`plantName` AS metric,\r\n (4095-`sensor_data`.`A`) AS `value`\r\nFROM `sensor_data`\r\nLEFT JOIN `sensor_links` ON\r\n`sensor_data`.`address` = `sensor_links`.`sensorAddress`\r\nWHERE $__timeFilter(`insertTime`)", + "refId": "Soil Moisture", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "sensor_data", + "timeColumn": "timestamp", + "timeColumnType": "int", + "where": [ + { + "name": "$__unixEpochFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Ambient Light", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "transformations": [ + { + "id": "seriesToColumns", + "options": { + "byField": "Time" + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": { + "Cactus Large": 2, + "Cactus Small": 4, + "Palm Tree": 3, + "Pineapple": 1, + "Time": 0 + }, + "renameByName": {} + } + } + ], + "transparent": true, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:66", + "decimals": 0, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:67", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "MySQL - Plant System", + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 31 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "options": { + "alertThreshold": false + }, + "percentage": false, + "pluginVersion": "7.5.4", + "pointradius": 5, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n UNIX_TIMESTAMP(`timestamp`) AS `time`,\r\n `sensor_links`.`plantName` AS metric,\r\n `waterVolume` AS `value`\r\nFROM `watering_data`\r\nLEFT JOIN `sensor_links` ON\r\n`watering_data`.`solenoidAddress` = `sensor_links`.`solenoidAddress`\r\nWHERE $__timeFilter(`timestamp`)", + "refId": "A", + "select": [ + [ + { + "params": [ + "waterVolume" + ], + "type": "column" + } + ] + ], + "table": "watering_data", + "timeColumn": "timestamp", + "timeColumnType": "datetime", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Watering data", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "transparent": true, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:756", + "format": "mlitre", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:757", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "1m", + "schemaVersion": 27, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "description": null, + "error": null, + "hide": 2, + "label": "Sensor_0x10", + "name": "Sensor_0x10", + "query": "Cactus", + "skipUrlSync": false, + "type": "constant" + }, + { + "description": null, + "error": null, + "hide": 2, + "label": "Sensor_0x11", + "name": "Sensor_0x11", + "query": "Palm Tree", + "skipUrlSync": false, + "type": "constant" + }, + { + "description": null, + "error": null, + "hide": 2, + "label": "Sensor_0x12", + "name": "Sensor_0x12", + "query": "Avocado Tree", + "skipUrlSync": false, + "type": "constant" + }, + { + "description": null, + "error": null, + "hide": 2, + "label": "Sensor_0x13", + "name": "Sensor_0x13", + "query": "Rose", + "skipUrlSync": false, + "type": "constant" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Plant Overview", + "uid": "VCPJlvuGz", + "version": 33 +} \ No newline at end of file diff --git a/Part3_Web_and_Automation/mysql/plantsystem.sql b/Part3_Web_and_Automation/mysql/plantsystem.sql new file mode 100644 index 0000000..7f8ff4d --- /dev/null +++ b/Part3_Web_and_Automation/mysql/plantsystem.sql @@ -0,0 +1,112 @@ +-- phpMyAdmin SQL Dump +-- version 5.1.0 +-- https://www.phpmyadmin.net/ +-- +-- Host: 192.168.0.25:3306 +-- Generation Time: Oct 22, 2021 at 02:07 AM +-- Server version: 8.0.24 +-- PHP Version: 7.4.16 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `plantsystem` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `sensor_data` +-- + +CREATE TABLE `sensor_data` ( + `id` int NOT NULL, + `insertTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `address` tinyint UNSIGNED NOT NULL, + `T` float UNSIGNED NOT NULL, + `M` smallint UNSIGNED NOT NULL, + `A` smallint UNSIGNED NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Sensor data'; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `sensor_links` +-- + +CREATE TABLE `sensor_links` ( + `id` int UNSIGNED NOT NULL, + `plantName` varchar(25) NOT NULL COMMENT 'Plant name', + `sensorAddress` tinyint UNSIGNED NOT NULL COMMENT 'I2C address of sensor attached to this plant', + `solenoidAddress` tinyint UNSIGNED NOT NULL COMMENT 'I2C address of solenoid attached to this plant' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `watering_data` +-- + +CREATE TABLE `watering_data` ( + `id` int UNSIGNED NOT NULL, + `solenoidAddress` tinyint UNSIGNED NOT NULL, + `waterVolume` smallint UNSIGNED NOT NULL, + `timestamp` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `sensor_data` +-- +ALTER TABLE `sensor_data` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `sensor_links` +-- +ALTER TABLE `sensor_links` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `watering_data` +-- +ALTER TABLE `watering_data` + ADD PRIMARY KEY (`id`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `sensor_data` +-- +ALTER TABLE `sensor_data` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `sensor_links` +-- +ALTER TABLE `sensor_links` + MODIFY `id` int UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `watering_data` +-- +ALTER TABLE `watering_data` + MODIFY `id` int UNSIGNED NOT NULL AUTO_INCREMENT; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/Part3_Web_and_Automation/n8n/PlantSystem_-_Periodic_Watering.json b/Part3_Web_and_Automation/n8n/PlantSystem_-_Periodic_Watering.json new file mode 100644 index 0000000..8581abd --- /dev/null +++ b/Part3_Web_and_Automation/n8n/PlantSystem_-_Periodic_Watering.json @@ -0,0 +1,319 @@ +{ + "name": "Watering System - Periodic Watering", + "nodes": [ + { + "parameters": {}, + "name": "Start", + "type": "n8n-nodes-base.start", + "typeVersion": 1, + "position": [ + 460, + 770 + ] + }, + { + "parameters": { + "operation": "executeQuery", + "query": "SELECT * FROM `sensor_links` WHERE `solenoidAddress` <> '0' ORDER BY `solenoidAddress` ASC" + }, + "name": "Select Solenoids", + "type": "n8n-nodes-base.mySql", + "typeVersion": 1, + "position": [ + 660, + 570 + ], + "credentials": { + "mySql": "NAS - MySQL" + } + }, + { + "parameters": { + "batchSize": 1, + "options": { + "reset": false + } + }, + "name": "For Each Solenoid", + "type": "n8n-nodes-base.splitInBatches", + "typeVersion": 1, + "position": [ + 850, + 570 + ], + "alwaysOutputData": true, + "continueOnFail": true + }, + { + "parameters": { + "url": "http://192.168.0.19/waterPlant", + "responseFormat": "string", + "options": {}, + "queryParametersUi": { + "parameter": [ + { + "name": "address", + "value": "={{$json[\"solenoidAddress\"]}}" + }, + { + "name": "volume", + "value": "={{$json[\"waterVolume\"]}}" + } + ] + } + }, + "name": "Water Plant", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 1, + "position": [ + 1260, + 570 + ], + "notesInFlow": false, + "notes": "Send request to water the plant with 100ml of water" + }, + { + "parameters": { + "table": "watering_data", + "columns": "solenoidAddress, waterVolume", + "options": {} + }, + "name": "Update `watering_data`", + "type": "n8n-nodes-base.mySql", + "typeVersion": 1, + "position": [ + 1450, + 770 + ], + "credentials": { + "mySql": "NAS - MySQL" + } + }, + { + "parameters": { + "functionCode": "const sleepTime = 25000; // in miliseconds\n\nfunction sleep(milliseconds) {\n return new Promise(\n resolve => setTimeout(resolve, milliseconds)\n );\n}\n// Sleep\nawait sleep(sleepTime );\n// Output data\nreturn items;\n" + }, + "name": "Delay", + "type": "n8n-nodes-base.function", + "typeVersion": 1, + "position": [ + 1450, + 570 + ], + "notesInFlow": false, + "notes": "Sleep" + }, + { + "parameters": { + "conditions": { + "number": [], + "boolean": [ + { + "value1": "={{$node[\"For Each Solenoid\"].context[\"noItemsLeft\"]}}", + "value2": true + } + ] + } + }, + "name": "IF", + "type": "n8n-nodes-base.if", + "typeVersion": 1, + "position": [ + 1660, + 320 + ] + }, + { + "parameters": {}, + "name": "NoOp", + "type": "n8n-nodes-base.noOp", + "typeVersion": 1, + "position": [ + 1860, + 420 + ] + }, + { + "parameters": { + "values": { + "number": [ + { + "name": "waterVolume", + "value": 50 + } + ] + }, + "options": {} + }, + "name": "Water Volume", + "type": "n8n-nodes-base.set", + "typeVersion": 1, + "position": [ + 1060, + 570 + ] + }, + { + "parameters": { + "chatId": "1254950103", + "text": "=Finished watering the plants!", + "additionalFields": {} + }, + "name": "Telegram", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1, + "position": [ + 1860, + 270 + ], + "credentials": { + "telegramApi": "Telegram N8N" + } + }, + { + "parameters": { + "triggerTimes": { + "item": [ + { + "hour": 5 + }, + { + "hour": 19 + } + ] + } + }, + "name": "Cron", + "type": "n8n-nodes-base.cron", + "typeVersion": 1, + "position": [ + 460, + 570 + ] + }, + { + "parameters": { + "path": "f7048627-a726-4344-8d49-e7ad19c4415a", + "options": {} + }, + "name": "Webhook", + "type": "n8n-nodes-base.webhook", + "typeVersion": 1, + "position": [ + 460, + 370 + ], + "webhookId": "f7048627-a726-4344-8d49-e7ad19c4415a" + } + ], + "connections": { + "Select Solenoids": { + "main": [ + [ + { + "node": "For Each Solenoid", + "type": "main", + "index": 0 + } + ] + ] + }, + "For Each Solenoid": { + "main": [ + [ + { + "node": "Water Volume", + "type": "main", + "index": 0 + } + ] + ] + }, + "Water Plant": { + "main": [ + [ + { + "node": "Delay", + "type": "main", + "index": 0 + }, + { + "node": "Update `watering_data`", + "type": "main", + "index": 0 + } + ] + ] + }, + "Delay": { + "main": [ + [ + { + "node": "IF", + "type": "main", + "index": 0 + } + ] + ] + }, + "IF": { + "main": [ + [ + { + "node": "NoOp", + "type": "main", + "index": 0 + }, + { + "node": "Telegram", + "type": "main", + "index": 0 + } + ], + [ + { + "node": "For Each Solenoid", + "type": "main", + "index": 0 + } + ] + ] + }, + "Water Volume": { + "main": [ + [ + { + "node": "Water Plant", + "type": "main", + "index": 0 + } + ] + ] + }, + "Cron": { + "main": [ + [ + { + "node": "Select Solenoids", + "type": "main", + "index": 0 + } + ] + ] + }, + "Webhook": { + "main": [ + [ + { + "node": "Select Solenoids", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": false, + "settings": {}, + "id": "8" +} \ No newline at end of file diff --git a/Part3_Web_and_Automation/n8n/PlantSystem_-_Read_Sensor_Data.json b/Part3_Web_and_Automation/n8n/PlantSystem_-_Read_Sensor_Data.json new file mode 100644 index 0000000..ba752fc --- /dev/null +++ b/Part3_Web_and_Automation/n8n/PlantSystem_-_Read_Sensor_Data.json @@ -0,0 +1,186 @@ +{ + "name": "Plant System - Read Sensor Data", + "nodes": [ + { + "parameters": {}, + "name": "Start", + "type": "n8n-nodes-base.start", + "typeVersion": 1, + "position": [ + 250, + 350 + ] + }, + { + "parameters": { + "url": "http://192.168.0.19/sensorData", + "allowUnauthorizedCerts": true, + "options": { + "followRedirect": true, + "ignoreResponseCode": true + } + }, + "name": "HTTP Request", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 1, + "position": [ + 500, + 350 + ], + "continueOnFail": true + }, + { + "parameters": { + "chatId": "1254950103", + "text": "=HousePlantSystem: Reading {{$node[\"HTTP Request\"].json[\"count\"]}} sensors instead of 4.", + "additionalFields": {} + }, + "name": "Telegram", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1, + "position": [ + 1000, + 150 + ], + "credentials": { + "telegramApi": "Telegram N8N" + } + }, + { + "parameters": { + "table": "sensor_data", + "columns": "address, T, M, A", + "options": {} + }, + "name": "MySQL", + "type": "n8n-nodes-base.mySql", + "typeVersion": 1, + "position": [ + 1000, + 350 + ], + "credentials": { + "mySql": "NAS - MySQL" + } + }, + { + "parameters": { + "functionCode": "const sensorData = [];\n\nfor (let i=0; i setTimeout(resolve, milliseconds)\n );\n}\n// Sleep\nawait sleep(sleepTime );\n// Output data\nreturn items;\n" + }, + "name": "Delay", + "type": "n8n-nodes-base.function", + "typeVersion": 1, + "position": [ + 1700, + 550 + ], + "notesInFlow": false, + "notes": "Sleep" + }, + { + "parameters": { + "conditions": { + "number": [], + "boolean": [ + { + "value1": "={{$node[\"For Each Solenoid\"].context[\"noItemsLeft\"]}}", + "value2": true + } + ] + } + }, + "name": "IF", + "type": "n8n-nodes-base.if", + "typeVersion": 1, + "position": [ + 1900, + 300 + ] + }, + { + "parameters": {}, + "name": "NoOp", + "type": "n8n-nodes-base.noOp", + "typeVersion": 1, + "position": [ + 2100, + 300 + ] + }, + { + "parameters": { + "values": { + "number": [ + { + "name": "waterVolume", + "value": 50 + } + ] + }, + "options": {} + }, + "name": "Water Volume", + "type": "n8n-nodes-base.set", + "typeVersion": 1, + "position": [ + 1300, + 550 + ] + }, + { + "parameters": { + "chatId": "1254950103", + "text": "=Watering {{$json[\"plantName\"]}} with {{$json[\"waterVolume\"]}}mL of water", + "additionalFields": {} + }, + "name": "Telegram", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1, + "position": [ + 1500, + 950 + ], + "credentials": { + "telegramApi": "Telegram N8N" + } + }, + { + "parameters": { + "path": "4d08ae89-8eba-4ee4-80c2-d8f93ff51adb", + "options": {} + }, + "name": "Webhook", + "type": "n8n-nodes-base.webhook", + "typeVersion": 1, + "position": [ + 700, + 390 + ], + "webhookId": "4d08ae89-8eba-4ee4-80c2-d8f93ff51adb" + } + ], + "connections": { + "Start": { + "main": [ + [ + { + "node": "Select Solenoids", + "type": "main", + "index": 0 + } + ] + ] + }, + "Select Solenoids": { + "main": [ + [ + { + "node": "For Each Solenoid", + "type": "main", + "index": 0 + } + ] + ] + }, + "For Each Solenoid": { + "main": [ + [ + { + "node": "Water Volume", + "type": "main", + "index": 0 + } + ] + ] + }, + "Delay": { + "main": [ + [ + { + "node": "IF", + "type": "main", + "index": 0 + } + ] + ] + }, + "Water Plant": { + "main": [ + [ + { + "node": "Delay", + "type": "main", + "index": 0 + } + ] + ] + }, + "IF": { + "main": [ + [ + { + "node": "NoOp", + "type": "main", + "index": 0 + } + ], + [ + { + "node": "For Each Solenoid", + "type": "main", + "index": 0 + } + ] + ] + }, + "Water Volume": { + "main": [ + [ + { + "node": "Update `watering_data`", + "type": "main", + "index": 0 + }, + { + "node": "Telegram", + "type": "main", + "index": 0 + }, + { + "node": "Water Plant", + "type": "main", + "index": 0 + } + ] + ] + }, + "Webhook": { + "main": [ + [ + { + "node": "Select Solenoids", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": true, + "settings": {}, + "id": "4" +} \ No newline at end of file diff --git a/Part3_Web_and_Automation/n8n/PlantSystem_-_Water_Specific_Plant.json b/Part3_Web_and_Automation/n8n/PlantSystem_-_Water_Specific_Plant.json new file mode 100644 index 0000000..2854a89 --- /dev/null +++ b/Part3_Web_and_Automation/n8n/PlantSystem_-_Water_Specific_Plant.json @@ -0,0 +1,208 @@ +{ + "name": "PlantSystem - Water Specific Plant", + "nodes": [ + { + "parameters": {}, + "name": "Start", + "type": "n8n-nodes-base.start", + "typeVersion": 1, + "position": [ + 800, + 750 + ] + }, + { + "parameters": { + "url": "http://192.168.0.19/waterPlant", + "responseFormat": "string", + "options": {}, + "queryParametersUi": { + "parameter": [ + { + "name": "address", + "value": "={{$json[\"solenoidAddress\"]}}" + }, + { + "name": "volume", + "value": "={{$node[\"Webhook\"].json[\"query\"][\"volume\"]}}" + } + ] + } + }, + "name": "Water Plant", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 1, + "position": [ + 1200, + 550 + ], + "notesInFlow": false, + "alwaysOutputData": true, + "continueOnFail": true, + "notes": "Send request to water the plant with 100ml of water" + }, + { + "parameters": { + "path": "756fac76-f3d7-4fce-b586-27e114afba46", + "options": {} + }, + "name": "Webhook", + "type": "n8n-nodes-base.webhook", + "typeVersion": 1, + "position": [ + 800, + 550 + ], + "webhookId": "756fac76-f3d7-4fce-b586-27e114afba46" + }, + { + "parameters": { + "operation": "executeQuery", + "query": "=SELECT * from `sensor_links` where `solenoidAddress` = '{{$json[\"query\"][\"solenoidAddress\"]}}' LIMIT 1" + }, + "name": "MySQL", + "type": "n8n-nodes-base.mySql", + "typeVersion": 1, + "position": [ + 1000, + 550 + ], + "credentials": { + "mySql": "NAS - MySQL" + } + }, + { + "parameters": { + "table": "watering_data", + "columns": "=solenoidAddress, waterVolume", + "options": {} + }, + "name": "Insert Water Amount", + "type": "n8n-nodes-base.mySql", + "typeVersion": 1, + "position": [ + 1810, + 450 + ], + "credentials": { + "mySql": "NAS - MySQL" + } + }, + { + "parameters": { + "functionCode": "items[0].json.waterVolume = $node[\"Webhook\"].json[\"query\"][\"volume\"];\nitems[0].json.solenoidAddress= $node[\"MySQL\"].json[\"solenoidAddress\"];\nreturn items;\n" + }, + "name": "Function", + "type": "n8n-nodes-base.function", + "typeVersion": 1, + "position": [ + 1610, + 450 + ] + }, + { + "parameters": { + "conditions": { + "string": [ + { + "value1": "={{$json[\"data\"]}}", + "operation": "contains", + "value2": "\"result\": OK" + } + ] + } + }, + "name": "IF", + "type": "n8n-nodes-base.if", + "typeVersion": 1, + "position": [ + 1400, + 550 + ] + }, + { + "parameters": { + "chatId": "1254950103", + "text": "=Water specific plant failed: Plant #{{$node[\"MySQL\"].json[\"sensorAddress\"]}} - Volume:{{$node[\"Webhook\"].json[\"query\"][\"volume\"]}}ml", + "additionalFields": {} + }, + "name": "Telegram", + "type": "n8n-nodes-base.telegram", + "typeVersion": 1, + "position": [ + 1600, + 650 + ], + "credentials": { + "telegramApi": "Telegram N8N" + } + } + ], + "connections": { + "Webhook": { + "main": [ + [ + { + "node": "MySQL", + "type": "main", + "index": 0 + } + ] + ] + }, + "MySQL": { + "main": [ + [ + { + "node": "Water Plant", + "type": "main", + "index": 0 + } + ] + ] + }, + "Function": { + "main": [ + [ + { + "node": "Insert Water Amount", + "type": "main", + "index": 0 + } + ] + ] + }, + "Water Plant": { + "main": [ + [ + { + "node": "IF", + "type": "main", + "index": 0 + } + ] + ] + }, + "IF": { + "main": [ + [ + { + "node": "Function", + "type": "main", + "index": 0 + } + ], + [ + { + "node": "Telegram", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": true, + "settings": {}, + "id": "5" +} \ No newline at end of file diff --git a/README.md b/README.md index 622f631..2ce6991 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,13 @@ Blog page: https://sasakaranovic.com/projects/diy-house-plants-watering-system-p Build watering system for house plants. In part two of this video series, we will create a central unit that takes sensor readings and also waters our plants on command. -## Part 3: Dashboard +## Part 3: Automation and Conclusion + +[![DIY House Plants Watering System - Part 3: Automation and Conclusion](http://i3.ytimg.com/vi/jLdTUMHOhRE/maxresdefault.jpg)](https://youtu.be/jLdTUMHOhRE) + +Watch: [DIY House Plants Watering System // Part 2: Automation and Conclusion](https://youtu.be/jLdTUMHOhRE) + +Blog page: https://sasakaranovic.com/projects/diy-house-plants-watering-system-part-3-automation/ + +Build watering system for house plants. In part two of this video series, we will create a central unit that takes sensor readings and also waters our plants on command. -TBD