[
    {
        "id": "7efaf915ca5b7337",
        "type": "tab",
        "label": "Awtrix weather by api.weather.gov",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "97e239f3b23160ca",
        "type": "group",
        "z": "7efaf915ca5b7337",
        "name": "Awtrix weather by api.weather.gov",
        "style": {
            "label": true
        },
        "nodes": [
            "514be84e6537b208",
            "a89bf6bc9b4ee6cd",
            "43c8034f31d87da1",
            "c3731eefae02dcb4",
            "ef31a5c5cd4dbcfc",
            "82f57ae3116cc75d",
            "0654e5b8038248e8",
            "d5cf1dbca661bcb3",
            "515b12b72d5e63dc",
            "8c1e5672f66cc334",
            "52931d15a219febb",
            "eb9f1cfe4f036184",
            "7071c05bfb9d9ac7",
            "97fb33089ff4fd73",
            "ece47f29798a9a1f",
            "eae9209dd318913e",
            "9e4bcd38a1a73d39",
            "95f76795e13faa31",
            "6824085062f5947f",
            "2ea88619e5304433",
            "a849b46631023e92",
            "b7d85c4da0f239fb"
        ],
        "x": 214,
        "y": 119,
        "w": 2092,
        "h": 482
    },
    {
        "id": "514be84e6537b208",
        "type": "http request",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "make weather request",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": true,
        "headers": [],
        "x": 1000,
        "y": 200,
        "wires": [
            [
                "43c8034f31d87da1",
                "515b12b72d5e63dc"
            ]
        ]
    },
    {
        "id": "a89bf6bc9b4ee6cd",
        "type": "inject",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "check",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "900",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 330,
        "y": 200,
        "wires": [
            [
                "d5cf1dbca661bcb3"
            ]
        ]
    },
    {
        "id": "43c8034f31d87da1",
        "type": "debug",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "debug weather response",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1250,
        "y": 380,
        "wires": []
    },
    {
        "id": "c3731eefae02dcb4",
        "type": "change",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "generate weather request",
        "rules": [
            {
                "t": "set",
                "p": "url",
                "pt": "msg",
                "to": "https://api.weather.gov/gridpoints/{wfo}/{x,y}/forecast/hourly",
                "tot": "str"
            },
            {
                "t": "change",
                "p": "url",
                "pt": "msg",
                "from": "{wfo}",
                "fromt": "str",
                "to": "wfo",
                "tot": "flow"
            },
            {
                "t": "change",
                "p": "url",
                "pt": "msg",
                "from": "{x,y}",
                "fromt": "str",
                "to": "x,y",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 750,
        "y": 200,
        "wires": [
            [
                "514be84e6537b208"
            ]
        ]
    },
    {
        "id": "ef31a5c5cd4dbcfc",
        "type": "catch",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "",
        "scope": null,
        "uncaught": false,
        "x": 580,
        "y": 560,
        "wires": [
            [
                "82f57ae3116cc75d"
            ]
        ]
    },
    {
        "id": "82f57ae3116cc75d",
        "type": "debug",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "debug errors",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 790,
        "y": 560,
        "wires": []
    },
    {
        "id": "0654e5b8038248e8",
        "type": "comment",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "Change configuration in this node",
        "info": "",
        "x": 540,
        "y": 160,
        "wires": []
    },
    {
        "id": "d5cf1dbca661bcb3",
        "type": "change",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "configuration",
        "rules": [
            {
                "t": "set",
                "p": "wfo",
                "pt": "flow",
                "to": "OKX",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "x,y",
                "pt": "flow",
                "to": "36,36",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "use_fahrenheit",
                "pt": "flow",
                "to": "true",
                "tot": "bool"
            },
            {
                "t": "set",
                "p": "awtrix_ip",
                "pt": "flow",
                "to": "192.168.1.101",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "awtrix_app_name",
                "pt": "flow",
                "to": "weather",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "authorization_header",
                "pt": "flow",
                "to": "Basic ZXhhbXBsZTpwYXNzd29yZA==",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 510,
        "y": 200,
        "wires": [
            [
                "c3731eefae02dcb4"
            ]
        ]
    },
    {
        "id": "515b12b72d5e63dc",
        "type": "function",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "frames generator",
        "func": "const LIFETIME = '3600';\nconst PUSH_ICON = '0';\nconst REPEAT = '2';\nconst DURATION = '';\n// Look ahead 30 mins\nconst TIME_OFFSET_IN_MS = 30 * 60 * 1000;\nconst USE_FAHRENHEIT = flow.get('use_fahrenheit');\n\n// Match keyword case insensitive from top to bottom\n// Put \"cloudy\" before \"mostly cloudy\" will cause latter one never matches\nconst KEYWORD_TO_ICON_DICT = {\n  'storm': 'stormy',\n  'foggy': 'foggy',\n  'snow': 'snowy',\n  'rain': 'rainy',\n  'partly cloudy': 'partly_cloudy',\n  'cloudy': 'mostly_cloudy',\n  'clear': 'moon',\n  'sunny': 'sunny',\n  '': 'weather_fallback',\n};\n\nconst createFrameWithTextAndIcon = (text, icon) => ({\n  text,\n  icon,\n  lifetime: LIFETIME,\n  pushIcon: PUSH_ICON,\n  repeat: REPEAT,\n  duration: DURATION,\n});\n\nconst mapShortForecastToIcon = (shortForecast) => {\n  for (const keyword of Object.keys(KEYWORD_TO_ICON_DICT)) {\n    if (shortForecast?.toLowerCase().includes(keyword?.toLowerCase())) {\n      return KEYWORD_TO_ICON_DICT[keyword];\n    }\n  }\n};\n\nconst findPeriodNow = (periods, timeOffsetInMs = TIME_OFFSET_IN_MS) => {\n  if (!Array.isArray(periods)) {\n    throw new Error('periods should be array');\n  }\n  const timestampInEpoch = Date.now() + TIME_OFFSET_IN_MS;\n  const found = periods.find(period => (new Date(period?.startTime)).valueOf() > timestampInEpoch);\n  if (!found) {\n    throw new Error(`unable to find period after ${timestampInEpoch}`);\n  }\n  return found;\n};\n\nconst FToC = (f, optionalDecimalPoints = 1) => Math.round((f - 32) * 5 / 9 * Math.pow(10, optionalDecimalPoints)) / Math.pow(10, optionalDecimalPoints);\n\nconst handleMessage = (message) => {\n  const periods = message?.payload?.properties?.periods;\n  if (!Array.isArray(periods)) {\n    throw new Error('unable to parse msessage');\n  }\n  const frames = [];\n  const currentPeriod = findPeriodNow(periods);\n  const temperatureText = USE_FAHRENHEIT ? `${currentPeriod?.temperature}°F` : `${FToC(currentPeriod?.temperature)}°C`;\n  frames.push(createFrameWithTextAndIcon(\n    temperatureText,\n    mapShortForecastToIcon(currentPeriod?.shortForecast),\n  ));\n  frames.push(createFrameWithTextAndIcon(\n    currentPeriod?.shortForecast,\n    mapShortForecastToIcon(currentPeriod?.shortForecast),\n  ));\n  frames.push(createFrameWithTextAndIcon(\n    `${currentPeriod?.probabilityOfPrecipitation?.value}%`,\n    'umbrella',\n  ));\n  frames.push(createFrameWithTextAndIcon(\n    // `${currentPeriod?.windSpeed} ${currentPeriod?.windDirection}`,\n    currentPeriod?.windSpeed,\n    'wind',\n  ));\n  frames.push(createFrameWithTextAndIcon(\n    `${currentPeriod?.relativeHumidity?.value}%`,\n    'humidity',\n  ));\n  message.payload.frames = frames;\n  return message;\n};\n\nreturn handleMessage(msg);",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1250,
        "y": 200,
        "wires": [
            [
                "8c1e5672f66cc334",
                "52931d15a219febb"
            ]
        ]
    },
    {
        "id": "8c1e5672f66cc334",
        "type": "debug",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "debug frames generator",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1530,
        "y": 380,
        "wires": []
    },
    {
        "id": "52931d15a219febb",
        "type": "change",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "generate awtrix request",
        "rules": [
            {
                "t": "set",
                "p": "method",
                "pt": "msg",
                "to": "POST",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "url",
                "pt": "msg",
                "to": "http://{awtrix_ip}/api/custom?name={awtrix_app_name}",
                "tot": "str"
            },
            {
                "t": "change",
                "p": "url",
                "pt": "msg",
                "from": "{awtrix_ip}",
                "fromt": "str",
                "to": "awtrix_ip",
                "tot": "flow"
            },
            {
                "t": "change",
                "p": "url",
                "pt": "msg",
                "from": "{awtrix_app_name}",
                "fromt": "str",
                "to": "awtrix_app_name",
                "tot": "flow"
            },
            {
                "t": "move",
                "p": "headers",
                "pt": "msg",
                "to": "original_headers",
                "tot": "msg"
            },
            {
                "t": "move",
                "p": "payload",
                "pt": "msg",
                "to": "original_payload",
                "tot": "msg"
            },
            {
                "t": "set",
                "p": "headers.Authorization",
                "pt": "msg",
                "to": "authorization_header",
                "tot": "flow"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "original_payload.frames",
                "tot": "msg",
                "dc": true
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1510,
        "y": 200,
        "wires": [
            [
                "eb9f1cfe4f036184",
                "7071c05bfb9d9ac7"
            ]
        ]
    },
    {
        "id": "eb9f1cfe4f036184",
        "type": "debug",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "debug awtrix request",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1820,
        "y": 380,
        "wires": []
    },
    {
        "id": "7071c05bfb9d9ac7",
        "type": "http request",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "make awtrix request",
        "method": "use",
        "ret": "txt",
        "paytoqs": "body",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [
            {
                "keyType": "Content-Type",
                "keyValue": "",
                "valueType": "application/json",
                "valueValue": ""
            }
        ],
        "x": 1860,
        "y": 200,
        "wires": [
            [
                "97fb33089ff4fd73"
            ]
        ]
    },
    {
        "id": "97fb33089ff4fd73",
        "type": "debug",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "debug awtrix response",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 2160,
        "y": 380,
        "wires": []
    },
    {
        "id": "ece47f29798a9a1f",
        "type": "inject",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "get WFO and gridX, gridY",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 370,
        "y": 440,
        "wires": [
            [
                "eae9209dd318913e"
            ]
        ]
    },
    {
        "id": "eae9209dd318913e",
        "type": "change",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "configuration",
        "rules": [
            {
                "t": "set",
                "p": "latitude",
                "pt": "msg",
                "to": "40.730610",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "longitude",
                "pt": "msg",
                "to": "-73.935242",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 590,
        "y": 440,
        "wires": [
            [
                "9e4bcd38a1a73d39"
            ]
        ]
    },
    {
        "id": "9e4bcd38a1a73d39",
        "type": "change",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "generate grid lookup request",
        "rules": [
            {
                "t": "set",
                "p": "url",
                "pt": "msg",
                "to": "https://api.weather.gov/points/{latitude},{longitude}",
                "tot": "str"
            },
            {
                "t": "change",
                "p": "url",
                "pt": "msg",
                "from": "{latitude}",
                "fromt": "str",
                "to": "latitude",
                "tot": "msg"
            },
            {
                "t": "change",
                "p": "url",
                "pt": "msg",
                "from": "{longitude}",
                "fromt": "str",
                "to": "longitude",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 840,
        "y": 440,
        "wires": [
            [
                "95f76795e13faa31"
            ]
        ]
    },
    {
        "id": "95f76795e13faa31",
        "type": "http request",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "make grid lookup request",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": true,
        "headers": [],
        "x": 1110,
        "y": 440,
        "wires": [
            [
                "6824085062f5947f",
                "2ea88619e5304433"
            ]
        ]
    },
    {
        "id": "6824085062f5947f",
        "type": "debug",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "debug grid lookup response",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1380,
        "y": 540,
        "wires": []
    },
    {
        "id": "2ea88619e5304433",
        "type": "template",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "",
        "field": "payload",
        "fieldType": "msg",
        "format": "handlebars",
        "syntax": "mustache",
        "template": "NWS Weather Forecast Office (WFO):\n{{payload.properties.gridId}}\nLocation gridX:\n{{payload.properties.gridX}}\nLocation gridY:\n{{payload.properties.gridY}}",
        "output": "str",
        "x": 1380,
        "y": 440,
        "wires": [
            [
                "a849b46631023e92"
            ]
        ]
    },
    {
        "id": "a849b46631023e92",
        "type": "debug",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "printout WFO and gridX, gridY",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1630,
        "y": 440,
        "wires": []
    },
    {
        "id": "b7d85c4da0f239fb",
        "type": "comment",
        "z": "7efaf915ca5b7337",
        "g": "97e239f3b23160ca",
        "name": "Change configuration in this node to get WFO and gridX, gridY needed for configuration above",
        "info": "",
        "x": 640,
        "y": 380,
        "wires": []
    }
]