[
    {
        "id": "merged_tuya_tab",
        "type": "tab",
        "label": "🔄 TUYA TOKEN + HTTP API MERGED",
        "disabled": false,
        "info": "Sloučený flow - automatický token refresh + HTTP endpointy\nToken refresh: každých 60 minut (3600s)\nHTTP port: 1881\nPRIMOTOP ACCOUNT: xmjrf7s594ek7ngm9sm3\nPRIMOTOP DEVICE: ebafafd9cd55a9bc02994x",
        "env": []
    },
    {
        "id": "global_token_init",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "🔧 GLOBAL TOKEN STORE INIT",
        "func": "// GLOBÁLNÍ STORAGE PRO ACCESS TOKEN\n// Inicializace při startu Node-RED\n\nif (!global.get('tuya_token')) {\n    global.set('tuya_token', {\n        access_token: null,\n        expires_at: 0,\n        last_refresh: 0\n    });\n    node.warn('🔄 Token storage inicializován');\n} else {\n    var token_data = global.get('tuya_token');\n    node.warn('📊 Token status: ' + JSON.stringify(token_data));\n}\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 200,
        "y": 60,
        "wires": [
            []
        ]
    },
    {
        "id": "auto_token_refresh",
        "type": "inject",
        "z": "merged_tuya_tab",
        "name": "⏰ Auto Refresh (60min)",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "3600",
        "crontab": "",
        "once": true,
        "onceDelay": 5,
        "topic": "",
        "payload": "{}",
        "payloadType": "json",
        "x": 190,
        "y": 140,
        "wires": [
            [
                "token_request_prepare"
            ]
        ]
    },
    {
        "id": "manual_token_refresh",
        "type": "inject",
        "z": "merged_tuya_tab",
        "name": "🔄 Manual Token Refresh",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{}",
        "payloadType": "json",
        "x": 190,
        "y": 200,
        "wires": [
            [
                "token_request_prepare"
            ]
        ]
    },
    {
        "id": "token_request_prepare",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "📝 Token Request Prepare",
        "func": "// TOKEN REQUEST PŘÍPRAVA - US WEST DATACENTER - PRIMOTOP ACCOUNT\nvar access_id = \"xmjrf7s594ek7ngm9sm3\";\nvar access_secret = \"ba95b549499349a688397f84cbb096fa\";\n\nvar timestamp = Date.now().toString();\nvar method = \"GET\";\nvar url_path = \"/v1.0/token?grant_type=1\";\n\n// Pro GET token request je content hash vždy prázdný string hash\nvar content_hash = \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\";\nvar string_to_sign = method + \"\\n\" + content_hash + \"\\n\" + \"\\n\" + url_path;\n\n// Pro token request NEPOUŽÍVÁME access_token (nemáme ho ještě)\nvar sign_str = access_id + timestamp + string_to_sign;\n\n// Příprava pro HMAC node\nmsg.payload = sign_str;\nmsg.key = access_secret;\n\n// Uložíme data pro další použití\nmsg.tuya_data = {\n    access_id: access_id,\n    timestamp: timestamp\n};\n\nnode.warn(\"🔄 REQUESTING NEW TOKEN (60min refresh)\");\nnode.warn(\"⏰ Timestamp: \" + timestamp);\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 480,
        "y": 170,
        "wires": [
            [
                "token_hmac_sign"
            ]
        ]
    },
    {
        "id": "token_hmac_sign",
        "type": "hmac",
        "z": "merged_tuya_tab",
        "name": "🔐 Token HMAC Sign",
        "algorithm": "HmacSHA256",
        "key": "key",
        "value": "payload",
        "x": 720,
        "y": 170,
        "wires": [
            [
                "token_http_prepare"
            ]
        ]
    },
    {
        "id": "token_http_prepare",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "🌐 Token HTTP Prepare",
        "func": "// SESTAVENÍ HTTP REQUEST PRO TOKEN\nvar signature = msg.payload.toUpperCase();\nvar data = msg.tuya_data;\n\nmsg.headers = {\n    \"Content-Type\": \"application/json\",\n    \"client_id\": data.access_id,\n    \"sign\": signature,\n    \"t\": data.timestamp,\n    \"sign_method\": \"HMAC-SHA256\"\n};\n\nmsg.payload = \"\"; // Prázdný payload pro GET\n\nnode.warn(\"✅ TOKEN SIGNATURE: \" + signature.substring(0, 30) + \"...\");\nnode.warn(\"🌐 REQUESTING TOKEN FROM US WEST\");\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 950,
        "y": 170,
        "wires": [
            [
                "token_api_request"
            ]
        ]
    },
    {
        "id": "token_api_request",
        "type": "http request",
        "z": "merged_tuya_tab",
        "name": "🔑 Token API Request",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "https://openapi.tuyaus.com/v1.0/token?grant_type=1",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 1180,
        "y": 170,
        "wires": [
            [
                "token_storage_handler"
            ]
        ]
    },
    {
        "id": "token_storage_handler",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "💾 Token Storage Handler",
        "func": "// ULOŽENÍ NOVÉHO TOKENU DO GLOBAL STORAGE\nvar response = msg.payload;\n\nif (response.success && response.result && response.result.access_token) {\n    var access_token = response.result.access_token;\n    var expire_time = response.result.expire_time || 7200; // default 2h\n    var now = Date.now();\n    \n    // Uložíme token do global storage\n    global.set('tuya_token', {\n        access_token: access_token,\n        expires_at: now + (expire_time * 1000),\n        last_refresh: now\n    });\n    \n    node.warn(\"✅ TOKEN ULOŽEN ÚSPĚŠNĚ! (60min refresh cycle)\");\n    node.warn(\"🔑 Token: \" + access_token.substring(0, 20) + \"...\");\n    node.warn(\"⏰ Expires in: \" + expire_time + \" seconds\");\n    \n    // Pošleme potvrzení\n    msg.payload = {\n        success: true,\n        token: access_token,\n        expires_in: expire_time,\n        token_preview: access_token.substring(0, 20) + \"...\"\n    };\n} else {\n    node.error(\"❌ TOKEN REQUEST FAILED!\");\n    node.error(\"Response: \" + JSON.stringify(response));\n    \n    msg.payload = {\n        success: false,\n        error: response\n    };\n}\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1420,
        "y": 170,
        "wires": [
            [
                "token_refresh_debug",
                "refresh_http_response"
            ]
        ]
    },
    {
        "id": "token_refresh_debug",
        "type": "debug",
        "z": "merged_tuya_tab",
        "name": "🔑 Token Refresh Debug",
        "active": true,
        "tosidebar": true,
        "console": true,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1670,
        "y": 140,
        "wires": []
    },
    {
        "id": "timer_display",
        "type": "inject",
        "z": "merged_tuya_tab",
        "name": "🕐 Timer Display (30s)",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "30",
        "crontab": "",
        "once": true,
        "onceDelay": 2,
        "topic": "",
        "payload": "{}",
        "payloadType": "json",
        "x": 190,
        "y": 280,
        "wires": [
            [
                "timer_status_update"
            ]
        ]
    },
    {
        "id": "timer_status_update",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "🕐 Timer Status Monitor",
        "func": "// TIMER STATUS S EMERGENCY REFRESH\nvar token_data = global.get('tuya_token') || {};\nvar now = Date.now();\n\nif (token_data.access_token) {\n    var expires_at = token_data.expires_at || 0;\n    var time_until_expiry = expires_at - now;\n    var minutes_until_expiry = Math.floor(time_until_expiry / 60000);\n    \n    var status_text = \"\";\n    var status_fill = \"green\";\n    \n    if (time_until_expiry <= 0) {\n        status_text = \"❌ TOKEN EXPIRED!\";\n        status_fill = \"red\";\n        \n        // EMERGENCY REFRESH\n        node.warn(\"🚨 EMERGENCY TOKEN REFRESH - TOKEN EXPIRED!\");\n        return [msg, {payload: {emergency: true}}];\n        \n    } else if (minutes_until_expiry < 5) {\n        status_text = \"🚨 \" + minutes_until_expiry + \"min KRITICKÉ!\";\n        status_fill = \"red\";\n        \n        // TRIGGER EMERGENCY REFRESH\n        var last_emergency = global.get('last_emergency_refresh') || 0;\n        if (now - last_emergency > 180000) { // 3 minuty cooldown\n            global.set('last_emergency_refresh', now);\n            node.warn(\"🚨 EMERGENCY REFRESH at \" + minutes_until_expiry + \" minutes!\");\n            return [msg, {payload: {emergency: true}}];\n        }\n        \n    } else if (minutes_until_expiry < 15) {\n        status_text = \"⚠️ \" + minutes_until_expiry + \"min do expirace\";\n        status_fill = \"yellow\";\n    } else if (minutes_until_expiry < 30) {\n        status_text = \"🔄 \" + minutes_until_expiry + \"min (OK)\";\n        status_fill = \"blue\";\n    } else {\n        status_text = \"✅ \" + minutes_until_expiry + \"min (SAFE)\";\n        status_fill = \"green\";\n    }\n    \n    node.status({\n        fill: status_fill,\n        shape: \"dot\",\n        text: status_text\n    });\n    \n} else {\n    node.status({\n        fill: \"red\",\n        shape: \"dot\",\n        text: \"❌ Žádný token!\"\n    });\n}\n\nreturn [msg, null];",
        "outputs": 2,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 450,
        "y": 280,
        "wires": [
            [],
            [
                "token_request_prepare"
            ]
        ]
    },
    {
        "id": "http_token_status",
        "type": "http in",
        "z": "merged_tuya_tab",
        "name": "GET /tuya/token/status",
        "url": "/tuya/token/status",
        "method": "get",
        "upload": false,
        "swaggerDoc": "",
        "x": 200,
        "y": 400,
        "wires": [
            [
                "token_status_response"
            ]
        ]
    },
    {
        "id": "token_status_response",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "📊 Token Status Response",
        "func": "// TOKEN STATUS PRO WEBOVÉ ROZHRANÍ\nvar token_data = global.get('tuya_token') || {};\nvar now = Date.now();\n\nif (token_data.access_token) {\n    var expires_at = token_data.expires_at || 0;\n    var minutes_until_expiry = Math.floor((expires_at - now) / 60000);\n    \n    msg.payload = {\n        success: true,\n        token_data: {\n            token_preview: token_data.access_token.substring(0, 20) + \"...\",\n            expires_at: expires_at,\n            minutes_remaining: Math.max(0, minutes_until_expiry)\n        }\n    };\n} else {\n    msg.payload = {\n        success: false,\n        error: \"No token available\"\n    };\n}\n\n// CORS headers\nmsg.headers = {\n    \"Content-Type\": \"application/json\",\n    \"Access-Control-Allow-Origin\": \"*\",\n    \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n    \"Access-Control-Allow-Headers\": \"Content-Type\"\n};\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 480,
        "y": 400,
        "wires": [
            [
                "http_response_status"
            ]
        ]
    },
    {
        "id": "http_response_status",
        "type": "http response",
        "z": "merged_tuya_tab",
        "name": "",
        "statusCode": "",
        "headers": {},
        "x": 710,
        "y": 400,
        "wires": []
    },
    {
        "id": "http_token_refresh",
        "type": "http in",
        "z": "merged_tuya_tab",
        "name": "POST /tuya/token/refresh",
        "url": "/tuya/token/refresh",
        "method": "post",
        "upload": false,
        "swaggerDoc": "",
        "x": 210,
        "y": 460,
        "wires": [
            [
                "token_request_prepare"
            ]
        ]
    },
    {
        "id": "refresh_http_response",
        "type": "http response",
        "z": "merged_tuya_tab",
        "name": "",
        "statusCode": "",
        "headers": {},
        "x": 1650,
        "y": 200,
        "wires": []
    },
    {
        "id": "http_switch_on",
        "type": "http in",
        "z": "merged_tuya_tab",
        "name": "POST /tuya/switch/on",
        "url": "/tuya/switch/on",
        "method": "post",
        "upload": false,
        "swaggerDoc": "",
        "x": 200,
        "y": 560,
        "wires": [
            [
                "prepare_switch_command"
            ]
        ]
    },
    {
        "id": "http_switch_off",
        "type": "http in",
        "z": "merged_tuya_tab",
        "name": "POST /tuya/switch/off",
        "url": "/tuya/switch/off",
        "method": "post",
        "upload": false,
        "swaggerDoc": "",
        "x": 200,
        "y": 620,
        "wires": [
            [
                "prepare_switch_command"
            ]
        ]
    },
    {
        "id": "http_switch_status",
        "type": "http in",
        "z": "merged_tuya_tab",
        "name": "GET /tuya/switch/status",
        "url": "/tuya/switch/status",
        "method": "get",
        "upload": false,
        "swaggerDoc": "",
        "x": 210,
        "y": 680,
        "wires": [
            [
                "prepare_switch_command"
            ]
        ]
    },
    {
        "id": "prepare_switch_command",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "🎯 Switch Command Prepare",
        "func": "// SWITCH COMMAND PŘÍPRAVA S AUTO TOKEN - PRIMOTOP ACCOUNT\nvar access_id = \"xmjrf7s594ek7ngm9sm3\";\nvar access_secret = \"ba95b549499349a688397f84cbb096fa\";\nvar device_id = \"ebafafd9cd55a9bc02994x\"; // Primotop device - SPRÁVNÉ ID\n\n// Extrakce příkazu z URL\nvar command = \"\";\nif (msg.req.url.includes('/on')) {\n    command = \"on\";\n} else if (msg.req.url.includes('/off')) {\n    command = \"off\";\n} else if (msg.req.url.includes('/status')) {\n    command = \"status\";\n}\n\n// Získání aktuálního tokenu z global storage\nvar token_data = global.get('tuya_token');\nif (!token_data || !token_data.access_token) {\n    msg.payload = {\n        success: false,\n        error: \"No token available\",\n        message: \"Please refresh token first\"\n    };\n    msg.statusCode = 401;\n    msg.headers = {\n        \"Content-Type\": \"application/json\",\n        \"Access-Control-Allow-Origin\": \"*\"\n    };\n    msg.is_http = true;\n    msg.http_res = msg.res;\n    return [null, msg];\n}\n\n// Kontrola expirace tokenu\nvar now = Date.now();\nvar time_until_expiry = token_data.expires_at - now;\nif (time_until_expiry <= 0) {\n    msg.payload = {\n        success: false,\n        error: \"Token expired\",\n        message: \"Token needs refresh\"\n    };\n    msg.statusCode = 401;\n    msg.headers = {\n        \"Content-Type\": \"application/json\",\n        \"Access-Control-Allow-Origin\": \"*\"\n    };\n    msg.is_http = true;\n    msg.http_res = msg.res;\n    return [null, msg];\n}\n\nvar access_token = token_data.access_token;\n\n// Store HTTP response object\nmsg.is_http = true;\nmsg.http_res = msg.res;\n\n// Rozhodnutí mezi GET (status) a POST (ovládání)\nif (command === \"status\") {\n    // GET request pro status\n    var timestamp = Date.now().toString();\n    var method = \"GET\";\n    var url_path = \"/v1.0/devices/\" + device_id;\n    var content_hash = \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\";\n    var string_to_sign = method + \"\\n\" + content_hash + \"\\n\" + \"\\n\" + url_path;\n    \n    msg.tuya_data = {\n        access_id: access_id,\n        access_token: access_token,\n        timestamp: timestamp,\n        device_id: device_id,\n        method: method,\n        url_path: url_path,\n        command_name: command\n    };\n    \n    var sign_str = access_id + access_token + timestamp + string_to_sign;\n    msg.payload = sign_str;\n    msg.key = access_secret;\n    \n    node.warn(\"❓ PŘÍPRAVA GET STATUS REQUEST\");\n} else {\n    // POST request pro switch control\n    var switch_value = (command === \"on\") ? true : false;\n    var commands = [{\"code\": \"switch_1\", \"value\": switch_value}];\n    var body = JSON.stringify({\"commands\": commands});\n    \n    msg.tuya_data = {\n        access_id: access_id,\n        access_secret: access_secret,\n        access_token: access_token,\n        device_id: device_id,\n        commands: commands,\n        body: body,\n        command_name: command,\n        method: \"POST\"\n    };\n    \n    // Připravíme body pro digest node\n    msg.payload = body;\n    \n    node.warn(\"🎯 PŘÍPRAVA \" + command.toUpperCase() + \" COMMAND\");\n}\n\nreturn msg;",
        "outputs": 2,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 490,
        "y": 620,
        "wires": [
            [
                "method_router"
            ],
            [
                "http_error_response"
            ]
        ]
    },
    {
        "id": "method_router",
        "type": "switch",
        "z": "merged_tuya_tab",
        "name": "🔀 Method Router",
        "property": "tuya_data.method",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "GET",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "POST",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 2,
        "x": 730,
        "y": 620,
        "wires": [
            [
                "get_status_hmac"
            ],
            [
                "post_body_digest"
            ]
        ]
    },
    {
        "id": "get_status_hmac",
        "type": "hmac",
        "z": "merged_tuya_tab",
        "name": "🔐 GET Status HMAC",
        "algorithm": "HmacSHA256",
        "key": "key",
        "value": "payload",
        "x": 960,
        "y": 560,
        "wires": [
            [
                "get_status_http"
            ]
        ]
    },
    {
        "id": "get_status_http",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "🌐 GET Status HTTP",
        "func": "// GET STATUS HTTP REQUEST\nvar signature = msg.payload.toUpperCase();\nvar data = msg.tuya_data;\n\nmsg.headers = {\n    \"Content-Type\": \"application/json\",\n    \"client_id\": data.access_id,\n    \"access_token\": data.access_token,\n    \"sign\": signature,\n    \"t\": data.timestamp,\n    \"sign_method\": \"HMAC-SHA256\"\n};\n\nmsg.url = \"https://openapi.tuyaus.com\" + data.url_path;\nmsg.method = \"GET\";\nmsg.payload = \"\";\n\nnode.warn(\"❓ ODESÍLÁM GET STATUS REQUEST\");\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1200,
        "y": 560,
        "wires": [
            [
                "switch_api_request"
            ]
        ]
    },
    {
        "id": "post_body_digest",
        "type": "digest",
        "z": "merged_tuya_tab",
        "name": "📝 POST Body Digest",
        "algorithm": "SHA256",
        "x": 960,
        "y": 680,
        "wires": [
            [
                "post_hmac_prepare"
            ]
        ]
    },
    {
        "id": "post_hmac_prepare",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "🔧 POST HMAC Prepare",
        "func": "// POST COMMAND HMAC PŘÍPRAVA\nvar data = msg.tuya_data;\nvar body_hash = msg.payload; // Z digest node\n\nvar timestamp = Date.now().toString();\nvar method = \"POST\";\nvar url_path = \"/v1.0/devices/\" + data.device_id + \"/commands\";\nvar string_to_sign = method + \"\\n\" + body_hash + \"\\n\" + \"\\n\" + url_path;\n\n// KRITICKÉ: Signature s access_token!\nvar sign_str = data.access_id + data.access_token + timestamp + string_to_sign;\n\nmsg.payload = sign_str;\nmsg.key = data.access_secret;\nmsg.tuya_data.timestamp = timestamp;\nmsg.tuya_data.url_path = url_path;\n\nnode.warn(\"🔧 POST HMAC s ACCESS_TOKEN\");\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1190,
        "y": 680,
        "wires": [
            [
                "post_command_hmac"
            ]
        ]
    },
    {
        "id": "post_command_hmac",
        "type": "hmac",
        "z": "merged_tuya_tab",
        "name": "🔐 POST Command HMAC",
        "algorithm": "HmacSHA256",
        "key": "key",
        "value": "payload",
        "x": 1440,
        "y": 680,
        "wires": [
            [
                "post_command_http"
            ]
        ]
    },
    {
        "id": "post_command_http",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "🌐 POST Command HTTP",
        "func": "// POST COMMAND HTTP REQUEST\nvar signature = msg.payload.toUpperCase();\nvar data = msg.tuya_data;\n\nmsg.headers = {\n    \"Content-Type\": \"application/json\",\n    \"client_id\": data.access_id,\n    \"access_token\": data.access_token,\n    \"sign\": signature,\n    \"t\": data.timestamp,\n    \"sign_method\": \"HMAC-SHA256\"\n};\n\nmsg.url = \"https://openapi.tuyaus.com\" + data.url_path;\nmsg.method = \"POST\";\nmsg.payload = {\"commands\": data.commands};\n\nnode.warn(\"🎯 ODESÍLÁM \" + data.command_name.toUpperCase() + \" COMMAND\");\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1220,
        "y": 740,
        "wires": [
            [
                "switch_api_request"
            ]
        ]
    },
    {
        "id": "switch_api_request",
        "type": "http request",
        "z": "merged_tuya_tab",
        "name": "🔌 Switch API Request",
        "method": "use",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 1480,
        "y": 620,
        "wires": [
            [
                "process_api_response"
            ]
        ]
    },
    {
        "id": "process_api_response",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "📤 Process API Response",
        "func": "// ZPRACOVÁNÍ ODPOVĚDI Z TUYA API\nvar response = msg.payload;\nvar command_name = msg.tuya_data.command_name;\n\n// Připravíme odpověď pro HTTP\nif (msg.is_http && msg.http_res) {\n    var httpResponse = {\n        success: true,\n        command: command_name,\n        timestamp: new Date().toISOString(),\n        device: \"Bily Primotop D1 1,5kW\"\n    };\n    \n    // Pro status přidej data\n    if (command_name === \"status\" && response.success) {\n        httpResponse.data = {\n            result: response.result\n        };\n    }\n    \n    // Pokud Tuya API vrátilo chybu\n    if (!response.success) {\n        httpResponse.success = false;\n        httpResponse.error = response.msg || \"Unknown error\";\n        httpResponse.code = response.code;\n    }\n    \n    msg.payload = httpResponse;\n    msg.statusCode = response.success ? 200 : 400;\n    \n    msg.headers = {\n        \"Content-Type\": \"application/json\",\n        \"Access-Control-Allow-Origin\": \"*\",\n        \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n        \"Access-Control-Allow-Headers\": \"Content-Type\"\n    };\n}\n\nnode.warn(\"✅ \" + command_name.toUpperCase() + \" odpověď: \" + (response.success ? \"SUCCESS\" : \"FAILED\"));\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1720,
        "y": 620,
        "wires": [
            [
                "http_command_response",
                "command_debug",
                "manual_test_debug"
            ]
        ]
    },
    {
        "id": "http_command_response",
        "type": "http response",
        "z": "merged_tuya_tab",
        "name": "",
        "statusCode": "",
        "headers": {},
        "x": 1950,
        "y": 620,
        "wires": []
    },
    {
        "id": "http_error_response",
        "type": "http response",
        "z": "merged_tuya_tab",
        "name": "",
        "statusCode": "",
        "headers": {},
        "x": 710,
        "y": 680,
        "wires": []
    },
    {
        "id": "command_debug",
        "type": "debug",
        "z": "merged_tuya_tab",
        "name": "🔌 Command Debug",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1960,
        "y": 680,
        "wires": []
    },
    {
        "id": "cors_options",
        "type": "http in",
        "z": "merged_tuya_tab",
        "name": "OPTIONS /tuya/*",
        "url": "/tuya/*",
        "method": "options",
        "upload": false,
        "swaggerDoc": "",
        "x": 180,
        "y": 780,
        "wires": [
            [
                "cors_handler"
            ]
        ]
    },
    {
        "id": "cors_handler",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "🌐 CORS Handler",
        "func": "// CORS pre-flight response\nmsg.headers = {\n    \"Access-Control-Allow-Origin\": \"*\",\n    \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n    \"Access-Control-Allow-Headers\": \"Content-Type\",\n    \"Access-Control-Max-Age\": \"86400\"\n};\n\nmsg.payload = \"\";\nmsg.statusCode = 200;\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 390,
        "y": 780,
        "wires": [
            [
                "cors_response"
            ]
        ]
    },
    {
        "id": "cors_response",
        "type": "http response",
        "z": "merged_tuya_tab",
        "name": "",
        "statusCode": "",
        "headers": {},
        "x": 590,
        "y": 780,
        "wires": []
    },
    {
        "id": "comment_token",
        "type": "comment",
        "z": "merged_tuya_tab",
        "name": "📝 TOKEN MANAGEMENT",
        "info": "Token refresh každých 60 minut\nEmergency refresh při < 5 minutách\nHTTP endpoints pro web UI",
        "x": 190,
        "y": 20,
        "wires": []
    },
    {
        "id": "comment_switch",
        "type": "comment",
        "z": "merged_tuya_tab",
        "name": "📝 SWITCH CONTROL",
        "info": "HTTP endpoints pro ovládání Primotop\nPřipraveno pro další switche\nDevice ID se dá snadno změnit",
        "x": 180,
        "y": 520,
        "wires": []
    },
    {
        "id": "manual_on_button",
        "type": "inject",
        "z": "merged_tuya_tab",
        "name": "🟢 Manual ON",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{}",
        "payloadType": "json",
        "x": 180,
        "y": 840,
        "wires": [
            [
                "prepare_manual_on"
            ]
        ]
    },
    {
        "id": "manual_off_button",
        "type": "inject",
        "z": "merged_tuya_tab",
        "name": "🔴 Manual OFF",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{}",
        "payloadType": "json",
        "x": 180,
        "y": 900,
        "wires": [
            [
                "prepare_manual_off"
            ]
        ]
    },
    {
        "id": "manual_status_button",
        "type": "inject",
        "z": "merged_tuya_tab",
        "name": "❓ Manual STATUS",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{}",
        "payloadType": "json",
        "x": 180,
        "y": 960,
        "wires": [
            [
                "prepare_manual_status"
            ]
        ]
    },
    {
        "id": "prepare_manual_on",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "🔧 Prepare Manual ON",
        "func": "// SIMULACE HTTP REQUEST PRO MANUAL ON TEST\nmsg.req = {\n    url: '/tuya/switch/on'\n};\n\n// Mark this as internal test\nmsg.is_manual_test = true;\n\nnode.warn('🟢 MANUAL ON TEST TRIGGERED');\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 420,
        "y": 840,
        "wires": [
            [
                "prepare_switch_command"
            ]
        ]
    },
    {
        "id": "prepare_manual_off",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "🔧 Prepare Manual OFF",
        "func": "// SIMULACE HTTP REQUEST PRO MANUAL OFF TEST\nmsg.req = {\n    url: '/tuya/switch/off'\n};\n\n// Mark this as internal test\nmsg.is_manual_test = true;\n\nnode.warn('🔴 MANUAL OFF TEST TRIGGERED');\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 420,
        "y": 900,
        "wires": [
            [
                "prepare_switch_command"
            ]
        ]
    },
    {
        "id": "prepare_manual_status",
        "type": "function",
        "z": "merged_tuya_tab",
        "name": "🔧 Prepare Manual STATUS",
        "func": "// SIMULACE HTTP REQUEST PRO MANUAL STATUS TEST\nmsg.req = {\n    url: '/tuya/switch/status'\n};\n\n// Mark this as internal test\nmsg.is_manual_test = true;\n\nnode.warn('❓ MANUAL STATUS TEST TRIGGERED');\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 420,
        "y": 960,
        "wires": [
            [
                "prepare_switch_command"
            ]
        ]
    },
    {
        "id": "manual_test_debug",
        "type": "debug",
        "z": "merged_tuya_tab",
        "name": "🧪 Manual Test Debug",
        "active": true,
        "tosidebar": true,
        "console": true,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1960,
        "y": 580,
        "wires": []
    },
    {
        "id": "comment_manual",
        "type": "comment",
        "z": "merged_tuya_tab",
        "name": "📝 MANUAL TESTING",
        "info": "Manuální tlačítka pro testování přímo z Node-RED\nON/OFF/STATUS - testuje Primotop přímo\nBez HTTP endpoint - pouze interní test",
        "x": 180,
        "y": 800,
        "wires": []
    }
]