Skip to content

Instantly share code, notes, and snippets.

@jwiegley
Created October 17, 2025 23:15
Show Gist options
  • Select an option

  • Save jwiegley/fa7c8ce7b01ccaef7751de053c42c6cf to your computer and use it in GitHub Desktop.

Select an option

Save jwiegley/fa7c8ce7b01ccaef7751de053c42c6cf to your computer and use it in GitHub Desktop.
[
{
"id": "86b277e82b069e9b",
"type": "server",
"name": "Home Assistant",
"version": 5,
"addon": false,
"rejectUnauthorizedCerts": true,
"ha_boolean": "y|yes|true|on|home|open",
"connectionDelay": true,
"cacheJson": true,
"heartbeat": false,
"heartbeatInterval": 30,
"areaSelector": "friendlyName",
"deviceSelector": "friendlyName",
"entitySelector": "friendlyName",
"statusSeparator": ": ",
"statusYear": "hidden",
"statusMonth": "short",
"statusDay": "numeric",
"statusHourCycle": "default",
"statusTimeFormat": "h:m",
"enableGlobalContextStore": false
},
{
"id": "cd11c03ec186c551",
"type": "prometheus-metric-config",
"name": "node_red_example",
"help": "An example I am trying out with Node-RED",
"labels": "label1",
"mtype": "counter"
},
{
"type": "tab",
"label": "Flow 1",
"id": "ba13e5bae3dfce24"
},
{
"id": "7c52d3e7111da0d0",
"type": "inject",
"z": "ba13e5bae3dfce24",
"name": "Every 10 minutes (24/7)",
"wires": [
[
"7adced677b906c23"
]
],
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "600",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 170,
"y": 460
},
{
"id": "7adced677b906c23",
"type": "http request",
"z": "ba13e5bae3dfce24",
"name": "KDA price on CoinGecko",
"wires": [
[
"7c3ca06cf270c119",
"api_success_counter"
]
],
"method": "GET",
"ret": "obj",
"paytoqs": "ignore",
"url": "https://api.coingecko.com/api/v3/simple/price?ids=kadena&vs_currencies=USD",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": true,
"headers": [
{
"keyType": "other",
"keyValue": "accept",
"valueType": "other",
"valueValue": "application/json"
}
],
"x": 150,
"y": 520
},
{
"id": "7c3ca06cf270c119",
"type": "change",
"z": "ba13e5bae3dfce24",
"name": "Extract USD",
"wires": [
[
"state_persistence_func"
]
],
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload.kadena.usd",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 110,
"y": 580
},
{
"id": "state_persistence_func",
"type": "function",
"z": "ba13e5bae3dfce24",
"name": "Calculate Change & Persist",
"wires": [
[
"bd9f62f0c362c5ee",
"kda_price_gauge",
"ha_sensor_update"
]
],
"func": "// Get last price from persistent context\nconst lastPrice = context.get('lastKdaPrice');\nconst currentPrice = msg.payload;\n\n// Calculate percentage change\nlet changePercent = 0;\nlet direction = '';\n\nif (lastPrice !== undefined && lastPrice !== null) {\n changePercent = ((currentPrice - lastPrice) / lastPrice) * 100;\n direction = changePercent > 0 ? '📈' : changePercent < 0 ? '📉' : '➡️';\n}\n\n// Store enriched data\nmsg.currentPrice = currentPrice;\nmsg.lastPrice = lastPrice || currentPrice;\nmsg.changePercent = changePercent;\nmsg.direction = direction;\n\n// Update context for next run\ncontext.set('lastKdaPrice', currentPrice);\n\n// Set payload for RBE node\nmsg.payload = currentPrice;\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 140,
"y": 620
},
{
"id": "bd9f62f0c362c5ee",
"type": "rbe",
"z": "ba13e5bae3dfce24",
"name": "Block unless >10%",
"wires": [
[
"7512302feda34bb4"
]
],
"func": "deadband",
"gap": "10%",
"start": "",
"inout": "out",
"septopics": true,
"property": "payload",
"topi": "topic",
"x": 130,
"y": 680
},
{
"id": "7512302feda34bb4",
"type": "api-call-service",
"z": "ba13e5bae3dfce24",
"name": "Enhanced Alert",
"wires": [
[
"de4ba89c7b3fbd8e"
]
],
"server": "86b277e82b069e9b",
"version": 7,
"debugenabled": true,
"action": "notify.mobile_app_johns_iphone_17_pro",
"floorId": [],
"areaId": [],
"deviceId": [],
"entityId": [],
"labelId": [],
"data": "{\n \"message\": \"KDA: $\" & $string(currentPrice) & \" (\" & direction & $formatNumber($abs(changePercent), '#.##') & \"% from $\" & $string(lastPrice) & \")\",\n \"title\": \"🚀 Kadena Price Alert\",\n \"data\": {\n \"url\": \"https://www.coingecko.com/en/coins/kadena\"\n }\n}",
"dataType": "jsonata",
"mergeContext": "",
"mustacheAltTags": false,
"outputProperties": [],
"queue": "none",
"blockInputOverrides": true,
"domain": "notify",
"service": "mobile_app_johns_iphone_17_pro",
"x": 120,
"y": 740
},
{
"id": "de4ba89c7b3fbd8e",
"type": "debug",
"z": "ba13e5bae3dfce24",
"name": "debug 4",
"wires": [],
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 100,
"y": 800
},
{
"id": "catch_errors",
"type": "catch",
"z": "ba13e5bae3dfce24",
"name": "Error Handler",
"wires": [
[
"error_debug",
"api_error_counter",
"error_notification"
]
],
"scope": [
"7adced677b906c23"
],
"uncaught": false,
"x": 350,
"y": 520
},
{
"id": "error_debug",
"type": "debug",
"z": "ba13e5bae3dfce24",
"name": "API Error",
"wires": [],
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 550,
"y": 480
},
{
"id": "error_notification",
"type": "function",
"z": "ba13e5bae3dfce24",
"name": "Rate Limit Errors",
"wires": [
[
"error_alert"
]
],
"func": "// Only alert if errors persist\nconst errorCount = context.get('errorCount') || 0;\ncontext.set('errorCount', errorCount + 1);\n\n// Alert after 3 consecutive errors\nif (errorCount >= 2) {\n context.set('errorCount', 0);\n return msg;\n}\nreturn null;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 570,
"y": 520
},
{
"id": "error_alert",
"type": "api-call-service",
"z": "ba13e5bae3dfce24",
"name": "Alert API Failure",
"wires": [
[]
],
"server": "86b277e82b069e9b",
"version": 7,
"debugenabled": false,
"action": "notify.mobile_app_johns_iphone_17_pro",
"floorId": [],
"areaId": [],
"deviceId": [],
"entityId": [],
"labelId": [],
"data": "{\"message\": \"CoinGecko API failing repeatedly\", \"title\": \"⚠️ KDA Monitor Error\"}",
"dataType": "jsonata",
"mergeContext": "",
"mustacheAltTags": false,
"outputProperties": [],
"queue": "none",
"blockInputOverrides": true,
"domain": "notify",
"service": "mobile_app_johns_iphone_17_pro",
"x": 790,
"y": 520
},
{
"id": "kda_price_gauge",
"type": "prometheus-exporter",
"z": "ba13e5bae3dfce24",
"name": "KDA Price Metric",
"wires": [],
"metric": "kda_price_metric_config",
"x": 360,
"y": 620
},
{
"id": "api_success_counter",
"type": "prometheus-exporter",
"z": "ba13e5bae3dfce24",
"name": "API Success",
"wires": [],
"metric": "kda_api_success_config",
"x": 360,
"y": 560
},
{
"id": "api_error_counter",
"type": "prometheus-exporter",
"z": "ba13e5bae3dfce24",
"name": "API Error",
"wires": [],
"metric": "kda_api_error_config",
"x": 550,
"y": 560
},
{
"id": "ha_sensor_update",
"type": "api-call-service",
"z": "ba13e5bae3dfce24",
"name": "Update HA Sensor",
"wires": [
[]
],
"server": "86b277e82b069e9b",
"version": 7,
"debugenabled": false,
"action": "input_number.set_value",
"floorId": [],
"areaId": [],
"deviceId": [],
"entityId": [
"input_number.kda_price_usd"
],
"labelId": [],
"data": "{\"value\": currentPrice}",
"dataType": "jsonata",
"mergeContext": "",
"mustacheAltTags": false,
"outputProperties": [],
"queue": "none",
"blockInputOverrides": false,
"domain": "input_number",
"service": "set_value",
"x": 360,
"y": 680
},
{
"id": "kda_price_metric_config",
"type": "prometheus-metric-config",
"name": "kda_price_usd",
"help": "Current Kadena (KDA) price in USD",
"labels": "",
"mtype": "gauge",
"z": "ba13e5bae3dfce24"
},
{
"id": "kda_api_success_config",
"type": "prometheus-metric-config",
"name": "kda_api_requests_total",
"help": "Total successful CoinGecko API requests for KDA price",
"labels": "status",
"mtype": "counter",
"z": "ba13e5bae3dfce24"
},
{
"id": "kda_api_error_config",
"type": "prometheus-metric-config",
"name": "kda_api_errors_total",
"help": "Total CoinGecko API errors for KDA price",
"labels": "error_type",
"mtype": "counter",
"z": "ba13e5bae3dfce24"
}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment