[
    {
        "id": "664b9b145a4ad916",
        "type": "tab",
        "label": "Persiana Cuarto",
        "disabled": false,
        "info": "Persiana: protección solar + térmica"
    },
    {
        "id": "d595f912058c98c1",
        "type": "inject",
        "z": "664b9b145a4ad916",
        "name": "Cada 30 min (6:00-22:00)",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "1800",
        "crontab": "",
        "once": true,
        "onceDelay": 10,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 150,
        "y": 100,
        "wires": [
            [
                "a70bb89796a9dabb"
            ]
        ]
    },
    {
        "id": "a70bb89796a9dabb",
        "type": "function",
        "z": "664b9b145a4ad916",
        "name": "¿Es de día?",
        "func": "const ahora = new Date();\nconst h = ahora.getHours() + ahora.getMinutes() / 60;\nif (h >= 6 && h < 22) { return msg; }\nreturn null;",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 350,
        "y": 100,
        "wires": [
            [
                "e763914120c916fb"
            ]
        ]
    },
    {
        "id": "e763914120c916fb",
        "type": "api-current-state",
        "z": "664b9b145a4ad916",
        "name": "Elevación Sol",
        "server": "ha_server",
        "version": 3,
        "outputs": 2,
        "halt_if": "",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "entity_id": "sun.sun",
        "state_type": "str",
        "blockInputOverrides": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            },
            {
                "property": "elevation",
                "propertyType": "msg",
                "value": "entity.attributes.elevation",
                "valueType": "jsonata"
            },
            {
                "property": "azimuth",
                "propertyType": "msg",
                "value": "entity.attributes.azimuth",
                "valueType": "jsonata"
            }
        ],
        "x": 530,
        "y": 100,
        "wires": [
            [
                "768bcb64605c4b4d"
            ],
            []
        ]
    },
    {
        "id": "768bcb64605c4b4d",
        "type": "api-current-state",
        "z": "664b9b145a4ad916",
        "name": "Viento OWM",
        "server": "ha_server",
        "version": 3,
        "outputs": 2,
        "halt_if": "",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "entity_id": "sensor.openweathermap_velocidad_del_viento",
        "state_type": "str",
        "blockInputOverrides": false,
        "outputProperties": [
            {
                "property": "wind_speed",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            },
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            }
        ],
        "x": 530,
        "y": 160,
        "wires": [
            [
                "78de4a106f635e9f"
            ],
            []
        ]
    },
    {
        "id": "78de4a106f635e9f",
        "type": "api-current-state",
        "z": "664b9b145a4ad916",
        "name": "Temp Tuya",
        "server": "ha_server",
        "version": 3,
        "outputs": 2,
        "halt_if": "",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "entity_id": "sensor.t_h_piso_cuarto_temperatura",
        "state_type": "str",
        "blockInputOverrides": false,
        "outputProperties": [
            {
                "property": "temp_tuya",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            },
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            }
        ],
        "x": 530,
        "y": 220,
        "wires": [
            [
                "e183123828782023"
            ],
            []
        ]
    },
    {
        "id": "e183123828782023",
        "type": "api-current-state",
        "z": "664b9b145a4ad916",
        "name": "Temp FP300",
        "server": "ha_server",
        "version": 3,
        "outputs": 1,
        "halt_if": "",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "entity_id": "sensor.aqara_presence_multisensor_fp300_temperatura",
        "state_type": "str",
        "blockInputOverrides": false,
        "outputProperties": [
            {
                "property": "temp_fp300",
                "propertyType": "msg",
                "value": "string",
                "valueType": "entityState"
            },
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "string",
                "valueType": "entityState"
            }
        ],
        "for": "",
        "forType": "num",
        "x": 530,
        "y": 280,
        "wires": [
            [
                "b0e43ffccb5c027f"
            ]
        ]
    },
    {
        "id": "b0e43ffccb5c027f",
        "type": "api-current-state",
        "z": "664b9b145a4ad916",
        "name": "Temp W100",
        "server": "ha_server",
        "version": 3,
        "outputs": 2,
        "halt_if": "",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "entity_id": "sensor.aqara_climate_sensor_w100_temperatura",
        "state_type": "str",
        "blockInputOverrides": false,
        "outputProperties": [
            {
                "property": "temp_w100",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            },
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            }
        ],
        "x": 530,
        "y": 340,
        "wires": [
            [
                "8ae58923bb7d9d8e"
            ],
            []
        ]
    },
    {
        "id": "8ae58923bb7d9d8e",
        "type": "function",
        "z": "664b9b145a4ad916",
        "name": "Calcular posición persiana",
        "func": "const v = {};\n\n// Elevación y azimut: desde msg o fallback al contexto global de HA\nconst elevRaw = msg.elevation ?? global.get('homeassistant.homeAssistant.states')?.['sensor.sol_sun_elevation']?.state;\nconst azimRaw = msg.azimuth  ?? global.get('homeassistant.homeAssistant.states')?.['sensor.sol_sun_azimuth']?.state;\n\nv.elev = parseFloat(String(elevRaw).replace(',', '.')) || 0;\nv.azim = parseFloat(String(azimRaw).replace(',', '.')) || 0;\nv.wind = parseFloat(String(msg.wind_speed).replace(',', '.')) || 0;\n\nv.t1 = isNaN(parseFloat(msg.temp_tuya))  ? 25 : parseFloat(String(msg.temp_tuya).replace(',', '.'));\nv.t2 = isNaN(parseFloat(msg.temp_fp300)) ? 25 : parseFloat(String(msg.temp_fp300).replace(',', '.'));\nv.t3 = isNaN(parseFloat(msg.temp_w100))  ? 25 : parseFloat(String(msg.temp_w100).replace(',', '.'));\nv.tMedia = (v.t1 + v.t2 + v.t3) / 3;\n\n//node.warn(`elev=${v.elev} azim=${v.azim} wind=${v.wind} tMedia=${v.tMedia.toFixed(1)}`);\n\n// PROTECCIÓN: viento fuerte\nif (v.wind > 40) {\n    msg.posicion = 100;\n    msg.motivo = `Viento ${v.wind} km/h. Persiana arriba`;\n    return msg;\n}\n\n// VENTANA AL ESTE (90°). Diferencia azimutal circular\nconst ventana = 90;\nconst difAzim = Math.min(\n    Math.abs(v.azim - ventana),\n    360 - Math.abs(v.azim - ventana)\n);\nconst solFrente = difAzim < 85;\n\n// Sol directo: azimut dentro del cono y elevación baja-media (<75°)\nconst solEntra = solFrente && v.elev > 3 && v.elev < 75;\n\nif (solEntra) {\n    const intensidad = 1 - (v.elev / 75);\n    const centrado = Math.max(0, 1 - (difAzim / 85));\n    const factor = Math.min(1, intensidad * 1.3 + centrado * 0.3);\n    let pos = 35 - (factor * 20);\n    msg.posicion = Math.round(Math.max(15, pos));\n    msg.motivo = `☀️ SOL DIRECTO. Azim:${v.azim.toFixed(0)}° Elev:${v.elev.toFixed(0)}° → ${msg.posicion}%`;\n} else {\n    let pos = 85;\n    if (v.tMedia > 28) pos = 75;\n    if (v.tMedia > 30) pos = 65;\n    if (v.tMedia > 32) pos = 50;\n    msg.posicion = pos;\n    msg.motivo = `🌤️ SIN SOL DIRECTO. Azim:${v.azim.toFixed(0)}° Elev:${v.elev.toFixed(0)}° Temp:${v.tMedia.toFixed(1)}°C → ${msg.posicion}%`;\n}\n\nreturn msg;",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 800,
        "y": 280,
        "wires": [
            [
                "a04675bff40e88ad"
            ]
        ]
    },
    {
        "id": "a04675bff40e88ad",
        "type": "api-call-service",
        "z": "664b9b145a4ad916",
        "name": "Mover persiana",
        "server": "ha_server",
        "version": 7,
        "debugenabled": false,
        "action": "cover.set_cover_position",
        "floorId": [],
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "labelId": [],
        "data": "{\"entity_id\": \"cover.smart_roller_shutter_25051571655872700801c4e7ae174929_shutter\", \"position\": $number(posicion)} ",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "blockInputOverrides": false,
        "domain": "cover",
        "service": "set_cover_position",
        "mergecontext": "",
        "x": 1050,
        "y": 280,
        "wires": [
            [
                "2b3d67840ff2bb5b"
            ]
        ]
    },
    {
        "id": "2b3d67840ff2bb5b",
        "type": "debug",
        "z": "664b9b145a4ad916",
        "name": "Log motivo",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "motivo",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1230,
        "y": 280,
        "wires": []
    },
    {
        "id": "e9d2bcd73df07a5e",
        "type": "inject",
        "z": "664b9b145a4ad916",
        "name": "Noche (22:00)",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "0 22 * * *",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 120,
        "y": 540,
        "wires": [
            [
                "019e774965b9c3f3"
            ]
        ]
    },
    {
        "id": "019e774965b9c3f3",
        "type": "api-current-state",
        "z": "664b9b145a4ad916",
        "name": "¿Viento noche?",
        "server": "ha_server",
        "version": 3,
        "outputs": 2,
        "halt_if": "",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "entity_id": "sensor.openweathermap_velocidad_del_viento",
        "state_type": "str",
        "blockInputOverrides": false,
        "outputProperties": [
            {
                "property": "viento_noche",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            },
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "entityState"
            }
        ],
        "x": 320,
        "y": 520,
        "wires": [
            [
                "0667e837ea142492"
            ],
            []
        ]
    },
    {
        "id": "0667e837ea142492",
        "type": "function",
        "z": "664b9b145a4ad916",
        "name": "¿Viento seguro?",
        "func": "const viento = parseFloat(msg.viento_noche) || 0;\nif (viento >= 40) {\n    msg.posicion = 100;\n    msg.motivo = `Noche + VIENTO (${viento} km/h). Persiana arriba`;\n} else {\n    msg.posicion = 75;\n    msg.motivo = `Noche tranquila. Persiana 75%`;\n}\nreturn msg;",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 540,
        "y": 500,
        "wires": [
            [
                "3cb71a4b56c2f5f2"
            ]
        ]
    },
    {
        "id": "3cb71a4b56c2f5f2",
        "type": "api-call-service",
        "z": "664b9b145a4ad916",
        "name": "Mover persiana (noche)",
        "server": "ha_server",
        "version": 7,
        "debugenabled": false,
        "action": "cover.set_cover_position",
        "floorId": [],
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "labelId": [],
        "data": "{\"entity_id\": \"cover.smart_roller_shutter_25051571655872700801c4e7ae174929_shutter\", \"position\": $number(posicion)} ",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [],
        "queue": "none",
        "blockInputOverrides": false,
        "domain": "cover",
        "service": "set_cover_position",
        "mergecontext": "",
        "x": 830,
        "y": 500,
        "wires": [
            [
                "5c0ddfbcc409419b"
            ]
        ]
    },
    {
        "id": "5c0ddfbcc409419b",
        "type": "debug",
        "z": "664b9b145a4ad916",
        "name": "Log noche",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "motivo",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1070,
        "y": 500,
        "wires": []
    },
    {
        "id": "ha_server",
        "type": "server",
        "name": "Home Assistant",
        "addon": true,
        "rejectUnauthorizedCerts": true,
        "ha_boolean": "y|yes|true|on|home|open",
        "connectionDelay": true,
        "cacheJson": true,
        "heartbeat": false,
        "heartbeatInterval": "30",
        "statusSeparator": " | "
    },
    {
        "id": "cf408a5ae79ac7c1",
        "type": "global-config",
        "env": [],
        "modules": {
            "node-red-contrib-home-assistant-websocket": "0.80.3"
        }
    }
]