{
  "name": "My workflow",
  "nodes": [
    {
      "parameters": {
        "jsCode": "// -------- Parameter  --------\nconst POLL_SEC   = 5;     // Trigger-Intervall (=Trigger-Knoten).\nconst START_W    = 10;    // Start ab 10W\nconst START_SEC  = 30;    // wenn mind 30 Sekunden > START_W = \"Running\"\nconst FINISH_W   = 5;     // Ende unter 5W\nconst FINISH_SEC = 60;    // wenn mind 60 Sekunden > FINISH_W = \"Idle\" (Finished)\n// --------------------------------------------------\n\nconst START_TICKS  = Math.ceil(START_SEC  / POLL_SEC);\nconst FINISH_TICKS = Math.ceil(FINISH_SEC / POLL_SEC);\n\n// --- apower vom HTTP-Node (kommt über Merge, steht bei dir auf Root) ---\nconst apower = (typeof $json.apower === 'number') ? $json.apower : Number($json.apower);\n\n// --- Sheet-Row SICHER holen: erstes Item des Sheets-Nodes ---\n// ACHTUNG: Node-Name exakt so, wie dein Lesen-Node heißt!\nconst SHEET_NODE = \"Daten Lesen - Status Waschmaschine (DB)\";\n\n// Hol alle Items vom Sheets-Node aus diesem Run:\nconst sheetItems = $items(SHEET_NODE);\nconst haveSheet = Array.isArray(sheetItems) && sheetItems.length > 0;\n\n// Falls nichts gefunden: Dummy-Zeile (damit der Code nicht crasht)\nconst s = haveSheet ? (sheetItems[0].json || {}) : {};\n\n// Status aus Sheet robust lesen\nlet state       = (typeof s.state === 'string' && s.state) ? s.state : 'idle';\nlet highcnt     = Number.isFinite(+s.highcnt)   ? +s.highcnt   : 0;\nlet lowcnt      = Number.isFinite(+s.lowcnt)    ? +s.lowcnt    : 0;\nlet laststartts = (s.laststartts && String(s.laststartts).length) ? String(s.laststartts) : null;\n\n// --- Zähler pflegen ---\nhighcnt = (apower > START_W)  ? (highcnt + 1) : 0;\nlowcnt  = (apower < FINISH_W) ? (lowcnt  + 1) : 0;\n\n// --- IDLE -> RUNNING ---\nif (state === 'idle' && highcnt >= START_TICKS) {\n  state = 'running';\n  lowcnt = 0;\n  // Verwende die lokale Zeitzone Europe/Berlin für den Zeitstempel\n  const localDate = new Date().toLocaleString('sv-SE', { timeZone: 'Europe/Berlin' });\n  laststartts = localDate.replace(' ', 'T') + 'Z';\n}\n\n// --- RUNNING -> IDLE (fertig) ---\nlet finishedNow = false;\nlet finishedAt  = null;\n\nif (state === 'running' && lowcnt >= FINISH_TICKS) {\n  state = 'idle';\n  highcnt = 0;\n  finishedNow = true;\n  // Verwende die lokale Zeitzone Europe/Berlin für den Zeitstempel\n  const localDate = new Date().toLocaleString('sv-SE', { timeZone: 'Europe/Berlin' });\n  finishedAt = localDate.replace(' ', 'T') + 'Z';\n}\n\n// --- Neues State-Objekt für Sheets-Write ---\nconst stateData = {\n  key: 'washer',\n  state,\n  highcnt,\n  lowcnt,\n  laststartts: laststartts || '',\n  // Verwende die lokale Zeitzone Europe/Berlin für den Zeitstempel\n  updatedat: new Date().toLocaleString('sv-SE', { timeZone: 'Europe/Berlin' }).replace(' ', 'T') + 'Z',\n};\n\n// --- Debug-Ausgabe, damit man sofort sieht, wo’s hakt ---\nconst debug = {\n  gotSheetRow: haveSheet,            // <- sollte true sein!\n  sheetRowRaw: s,                    // was genau aus Sheets kam\n  apowerSeen: apower,                // gemessene Leistung\n  ticks: { start: START_TICKS, finish: FINISH_TICKS },\n  thresholds: { START_W, FINISH_W }\n};\n\n// IMMER 1 Item ausgeben; IF filtert auf finished===true\nreturn [{\n  json: {\n    // für IF + E-Mail:\n    finished: finishedNow,\n    apower,\n    startedAt: laststartts || null,\n    finishedAt,\n\n    // zum Sheets-Write:\n    stateData,\n\n    // Debug:\n    debug\n  }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        544,
        320
      ],
      "id": "708c9e84-7db5-4196-a168-8283266b72cf",
      "name": "Code"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [
        320,
        320
      ],
      "id": "6a3c8885-46ab-467a-a0bd-1a5a811a8862",
      "name": "Merge"
    },
    {
      "parameters": {
        "url": "http://192.168.1.100/rpc/Switch.GetStatus?id=0",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        96,
        224
      ],
      "id": "4ad8075b-e882-4961-8076-3ce26cd8ff54",
      "name": "Daten vom Shelly Plug"
    },
    {
      "parameters": {
        "fromEmail": "n8n@versenderadresse.de",
        "toEmail": "fertig@empfängeradresse.de",
        "subject": "Die Waschmaschine ist fertig !!!",
        "html": "=Start:  {{ $json.startedAt\n  ? new Date($json.startedAt).toLocaleString('de-DE', {\n      year:'numeric', month:'2-digit', day:'2-digit', hour:'2-digit', minute:'2-digit'\n    })\n  : '–' }} Uhr\n<br>\nEnde:   {{ $json.finishedAt\n  ? new Date($json.finishedAt).toLocaleString('de-DE', {\n      year:'numeric', month:'2-digit', day:'2-digit', hour:'2-digit', minute:'2-digit'\n    })\n  : '–' }} Uhr\n<br><br>\nLetzter Messwert: {{ $json.apower }} W",
        "options": {}
      },
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        992,
        416
      ],
      "id": "0f034719-2eff-43f5-8dec-1545756e9eab",
      "name": "Fertigmeldung",
      "webhookId": "254d4412-435b-434a-8166-a7e8dfa2e813",
      "credentials": {
        "smtp": {
          "id": "LDk7XIcRXQlMzOgj",
          "name": "n8n@versenderadresse.de"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "b9110b37-1fd2-4f35-a995-45175e3b15c5",
              "leftValue": "={{ $node[\"Code\"].json[\"finished\"] }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        768,
        416
      ],
      "id": "7a8ec779-3f4e-4a72-8c25-380058e77361",
      "name": "Maschine fertig?"
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT key, state, highcnt, lowcnt, laststartts, updatedat\nFROM public.washer_state\nWHERE key = 'washer'\nLIMIT 1;",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        96,
        416
      ],
      "id": "74e8a722-5046-45d6-9f8d-230eb6c2cc6f",
      "name": "Daten Lesen - Status Waschmaschine (DB)",
      "credentials": {
        "postgres": {
          "id": "dsAxdCgZJ8kPB2tW",
          "name": "PostgreSQL n8n"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO public.washer_state (key, state, highcnt, lowcnt, laststartts, updatedat)\nVALUES (\n  'washer',\n  '{{$json.stateData.state}}',\n  {{$json.stateData.highcnt}},\n  {{$json.stateData.lowcnt}},\n  {{ $json.stateData.laststartts ? \"'\" + $json.stateData.laststartts + \"'::timestamptz\" : \"NULL\" }},\n  '{{$json.stateData.updatedat}}'::timestamptz\n)\nON CONFLICT (key) DO UPDATE SET\n  state       = EXCLUDED.state,\n  highcnt     = EXCLUDED.highcnt,\n  lowcnt      = EXCLUDED.lowcnt,\n  laststartts = EXCLUDED.laststartts,\n  updatedat   = EXCLUDED.updatedat;",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        784,
        224
      ],
      "id": "e9acb51f-83d7-4446-be25-3228eb9f7f22",
      "name": "Status in Datenbank schreiben",
      "credentials": {
        "postgres": {
          "id": "dsAxdCgZJ8kPB2tW",
          "name": "PostgreSQL n8n"
        }
      }
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "seconds",
              "secondsInterval": 5
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -128,
        320
      ],
      "id": "aa4cfbda-95a3-4c49-ac0f-478840fea67b",
      "name": "Trigger alle 5 Sekunden"
    }
  ],
  "pinData": {},
  "connections": {
    "Code": {
      "main": [
        [
          {
            "node": "Maschine fertig?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Status in Datenbank schreiben",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daten vom Shelly Plug": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Maschine fertig?": {
      "main": [
        [
          {
            "node": "Fertigmeldung",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daten Lesen - Status Waschmaschine (DB)": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Trigger alle 5 Sekunden": {
      "main": [
        [
          {
            "node": "Daten vom Shelly Plug",
            "type": "main",
            "index": 0
          },
          {
            "node": "Daten Lesen - Status Waschmaschine (DB)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "dcfbddb3-78cb-43b4-afde-e595718170f7",
  "meta": {
    "instanceId": "ffe0b70cc577e9b348f8b959bbfec3f08e5dd04236a3439c4dcac1907ffb5606"
  },
  "id": "dm1hy1JBOqaBXghS",
  "tags": []
}