I’m on NR 17.0.4 and HA Core 2024.1.6. I’m getting a new error after the upgrade to 17.0.4:
TypeError: Cannot read properties of undefined (reading 'replace')
This is appearing for all of my iOS actionable notifications, using the subflow originally put together by zachowj:
[{"id":"3586791854cfef41","type":"function","z":"6dc0247c.d7210c","name":"create service call","func":"\nmsg._originalPayload = msg.payload;\nflow.set('latestMessage', msg);\n\nvar xTitle = \"\";\nvar xSubtitle = \"\";\nvar xMessage = \"\";\nvar xServices = \"\";\nvar xTag = \"\";\nvar xUrl = \"\";\n\n// overrides\nif (typeof msg.notificationOverride !== 'undefined' && msg.notificationOverride !== null) {\n if (typeof msg.notificationOverride.title !== 'undefined' && msg.notificationOverride.title !=='' && msg.notificationOverride.title !== null){\n xTitle = msg.notificationOverride.title;\n } else {\n xTitle = env.get('title');\n }\n if (typeof msg.notificationOverride.subtitle !== 'undefined' && msg.notificationOverride.subtitle !=='' && msg.notificationOverride.subtitle !== null){\n xSubtitle = msg.notificationOverride.subtitle;\n } else {\n xSubtitle = env.get('subtitle');\n }\n if (typeof msg.notificationOverride.message !== 'undefined' && msg.notificationOverride.message !=='' && msg.notificationOverride.message !== null){\n xMessage = msg.notificationOverride.message;\n } else {\n xMessage = env.get('message');\n }\n if (typeof msg.notificationOverride.url !== 'undefined' && msg.notificationOverride.url !=='' && msg.notificationOverride.url !== null){\n xUrl = msg.notificationOverride.url;\n } else {\n xUrl = env.get('notificationUrl');\n }\n if (typeof msg.notificationOverride.services !== 'undefined' && msg.notificationOverride.services !=='' && msg.notificationOverride.services !== null){\n xServices = msg.notificationOverride.services;\n } else {\n xServices = env.get('service');\n }\n flow.set('service', xServices);\n if (typeof msg.notificationOverride.tag !== 'undefined' && msg.notificationOverride.tag !=='' && msg.notificationOverride.tag !== null){\n xTag = msg.notificationOverride.tag;\n } else {\n if (env.get('tag') !== '') {\n xTag = `${env.get('tag').replace(/[^\\w\\s]/gi, '').replace(/\\s+/g,'_').toUpperCase()}`;\n } else {\n // need to still set this to something in case clear_notification is sent.\n xTag = `${env.get('title').replace(/[^\\w\\s]/gi, '').replace(/\\s+/g,'_').toUpperCase()}_${flow.get('random')}`;\n } \n }\n flow.set('tag',xTag);\n} else {\n // If no override is sent in...\n if (env.get('tag') !== '') {\n xTag = `${env.get('tag').replace(/[^\\w\\s]/gi, '').replace(/\\s+/g,'_').toUpperCase()}`;\n } else {\n // need to still set this to something in case clear_notification is sent.\n xTag = `${env.get('title').replace(/[^\\w\\s]/gi, '').replace(/\\s+/g,'_').toUpperCase()}_${flow.get('random')}`;\n } \n flow.set('tag',xTag);\n \n xServices = env.get('service');\n flow.set('service', xServices);\n \n xTitle = env.get('title');\n xSubtitle = env.get('subtitle');\n xMessage = env.get('message');\n xUrl = env.get('notificationUrl');\n}\n\n\n\nconst services = flow.get('service');\nif(!services) {\n node.status({\n text: 'no services defined',\n shape: 'ring',\n fill: 'red'\n });\n return; \n} else if (services == \"NOONE\"){\n node.status({\n text: 'No one to send to',\n shape: 'ring',\n fill: 'yellow'\n });\n return;\n}\n\n\n\n// create actions\nconst actions = [];\n[1,2,3,4].forEach(i => {\n const name = `action${i}`\n if (env.get(`${name}Title`) !== ''){\n const action = env.get(`${name}Title`).replace(/[^\\w\\s]/gi, '').replace(/\\s+/g,'_').toUpperCase();\n const title = env.get(`${name}Title`);\n const activationMode = env.get(`${name}ActivationMode`); \n \n const uri = env.get(`${name}Uri`);\n const textInputButtonTitle = env.get(`${name}TextInputButtonTitle`);\n const textInputPlaceholder = env.get(`${name}TextInputPlaceHolder`);\n const authenticationRequired = env.get(`${name}AuthenticationRequired`);\n const destructive = env.get(`${name}Destructive`);\n const behavior = env.get(`${name}Behavior`);\n const icon = env.get(`${name}Icon`);\n \n const actionObject = {};\n actionObject.action = action;\n actionObject.title = title;\n actionObject.activationMode = activationMode;\n \n if (uri != \"\") actionObject.uri = uri;\n if (textInputButtonTitle != \"\") actionObject.textInputButtonTitle = textInputButtonTitle;\n if (textInputPlaceholder != \"\") actionObject.textInputPlaceholder = textInputPlaceholder;\n if (authenticationRequired != \"\") actionObject.authenticationRequired = authenticationRequired;\n if (destructive != \"\") actionObject.destructive = destructive;\n if (behavior != \"\") actionObject.behavior = behavior;\n if (icon != \"\") actionObject.icon = icon;\n \n actions.push(actionObject);\n }\n});\n\n// create msg object\n\nmsg.payload = {\n domain: 'notify',\n data: {\n title: xTitle,\n message: xMessage,\n data: {\n push: {},\n tag: xTag\n }\n }\n };\n\nif (actions.length > 0) {\n msg.payload.data.data.action_data = {tag: xTag};\n msg.payload.data.data.actions = actions;\n \n}\n\n\n// notification url\nif (xUrl !== \"\") {\n msg.payload.data.data.url = {};\n msg.payload.data.data.url = xUrl;\n}\n\n// subtitle\nif (xSubtitle !== '') {\n msg.payload.data.data.subtitle = xSubtitle;\n}\n\n// sound information\nmsg.payload.data.data.push.sound = {};\nif (env.get('customSound').length > 0){\n msg.payload.data.data.push.sound.name = env.get('customSound');\n} else if (env.get('customSoundPreInstalled').length > 0) {\n msg.payload.data.data.push.sound.name = env.get('customSoundPreInstalled');\n} else {\n msg.payload.data.data.push.sound.name = 'default';\n}\nif (env.get('isCriticalNotification')) {\n msg.payload.data.data.push.sound.critical = 1;\n msg.payload.data.data.push.sound.volume = 1.0;\n}\n\n// group thread id\nif (env.get('group') !== '') {\n msg.payload.data.data.group = env.get('group');\n}\n\n// Map Information\nif (env.get('latitudeFirst') !== 0 && env.get('longitudeFirst') !== 0){\n msg.payload.data.data.action_data.latitude = env.get('latitudeFirst');\n msg.payload.data.data.action_data.longitude = env.get('longitudeFirst');\n if (env.get('latitudeSecond') !== 0 && env.get('longitudeSecond') !== 0){\n msg.payload.data.data.action_data.second_latitude = env.get('latitudeSecond');\n msg.payload.data.data.action_data.second_longitude = env.get('longitudeSecond');\n // add in all the extras, which default to false.\n msg.payload.data.data.action_data.shows_line_between_points = env.get('showLineBetweenPoints');\n msg.payload.data.data.action_data.shows_compass = env.get('showCompass');\n msg.payload.data.data.action_data.shows_points_of_interest = env.get('showPointsOfInterest');\n msg.payload.data.data.action_data.shows_scale = env.get('showScale');\n msg.payload.data.data.action_data.shows_traffic = env.get('showTraffic');\n msg.payload.data.data.action_data.shows_user_location = env.get('showUserLocation');\n }\n}\n// camera information\nif (env.get('cameraEntity') !== '') {\n msg.payload.data.data.entity_id = env.get('cameraEntity');\n}\n// media information\nif (env.get('contentUrl') !== '') {\n\n} else {\n if (env.get('imagePath') !== '') {\n msg.payload.data.data.image = env.get('imagePath');\n }\n if (env.get('videoPath') !== '') {\n msg.payload.data.data.video = env.get('videoPath');\n }\n if (env.get('audioPath') !== '') {\n msg.payload.data.data.audio = env.get('audioPath');\n }\n}\nif (env.get('contentUrl') !== '' || env.get('imagePath') !== '' || env.get('videoPath') !== '' || env.get('audioPath') !== '') {\n if (env.get('lazyLoading')) {\n msg.payload.data.data.lazy = env.get('lazyLoading');\n }\n if (env.get('hideThumbnail')) {\n msg.payload.data.data.attachment = {};\n msg.payload.data.data.attachment['hide-thumbnail'] = env.get('hideThumbnail');\n }\n}\n\nservices.trim().split(/,\\s*/).forEach(service => {\n if(!service) return;\n msg.payload.service = service;\n node.send(msg);\n});\n\nnode.done();","outputs":1,"noerr":0,"initialize":"flow.set('random',Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5).toUpperCase());","finalize":"","libs":[],"x":430,"y":80,"wires":[["84115d3979a0b0b6"]]},{"id":"90ab222038404541","type":"switch","z":"6dc0247c.d7210c","name":"which action?","property":"responseIndex","propertyType":"flow","rules":[{"t":"eq","v":"1","vt":"num"},{"t":"eq","v":"2","vt":"num"},{"t":"eq","v":"3","vt":"num"},{"t":"eq","v":"4","vt":"num"}],"checkall":"true","repair":false,"outputs":4,"x":1280,"y":380,"wires":[[],[],[],[]]},{"id":"f3d74762ed30ae54","type":"status","z":"6dc0247c.d7210c","name":"","scope":["3586791854cfef41","b1e2e20511543565","fcf9f9c27469a607","6fdf5748e207aa7e"],"x":100,"y":320,"wires":[[]]},{"id":"b1e2e20511543565","type":"function","z":"6dc0247c.d7210c","name":"build message","func":"const latestMessage = flow.get('latestMessage');\nconst event = msg.payload.event;\n\n\nlatestMessage.payload = latestMessage._originalPayload;\nlatestMessage.eventData = msg.payload;\ndelete latestMessage._originalPayload;\n\nif(env.get('userInfo')) {\n const userData = msg.userData.find(u => u.id === msg.payload.context.user_id);\n latestMessage.userData = userData;\n}\nnode.warn('title: ' + env.get('title'));\nnode.warn('1: ' + env.get(`action1Title`));\nnode.warn('2: ' + env.get(`action2Title`));\nnode.warn('3: ' + env.get(`action3Title`));\nnode.warn('4: ' + env.get(`action4Title`));\n\nconst index = [1,2,3,4].find(i => env.get(`action${i}Title`).replace(/[^\\w\\s]/gi, '').replace(/\\s+/g,'_').toUpperCase() === event.actionName);\nflow.set(\"responseIndex\",index);\nnode.status({\n text: `${env.get(`action${index}Title`).replace(/[^\\w\\s]/gi, '').replace(/\\s+/g,'_').toUpperCase()} at: ${getPrettyDate()}`,\n shape: 'dot',\n fill: 'green'\n});\n\nreturn latestMessage;\n\n\nfunction getPrettyDate() {\n return new Date().toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n hour12: false,\n hour: 'numeric',\n minute: 'numeric',\n });\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1080,"y":380,"wires":[["90ab222038404541"]]},{"id":"a7d52acc08b671e0","type":"switch","z":"6dc0247c.d7210c","name":"belongs here?","property":"payload.event.action_data.tag","propertyType":"msg","rules":[{"t":"eq","v":"tag","vt":"flow"}],"checkall":"true","repair":false,"outputs":1,"x":412,"y":256,"wires":[["a69ed312811b3a6d"]]},{"id":"7bc5c379b10a2fbf","type":"ha-api","z":"6dc0247c.d7210c","name":"get user info","server":"296c0678.b5f9ca","version":1,"debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{\"type\": \"config/auth/list\"}","dataType":"json","responseType":"json","outputProperties":[{"property":"userData","propertyType":"msg","value":"","valueType":"results"}],"x":950,"y":320,"wires":[["b1e2e20511543565"]]},{"id":"c25a82298fbaad78","type":"switch","z":"6dc0247c.d7210c","name":"fetch user info?","property":"userInfo","propertyType":"env","rules":[{"t":"true"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":800,"y":380,"wires":[["7bc5c379b10a2fbf"],["b1e2e20511543565"]]},{"id":"b738bc2e474ec4a5","type":"server-events","z":"6dc0247c.d7210c","name":"ios.notification_action_fired","server":"296c0678.b5f9ca","version":3,"exposeAsEntityConfig":"","eventType":"ios.notification_action_fired","waitForRunning":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"$outputData(\"eventData\").event_type","valueType":"jsonata"},{"property":"event_type","propertyType":"msg","value":"$outputData(\"eventData\").event_type","valueType":"jsonata"}],"x":164,"y":256,"wires":[["a7d52acc08b671e0"]]},{"id":"fcf9f9c27469a607","type":"api-call-service","z":"6dc0247c.d7210c","name":"Send Notifications","server":"296c0678.b5f9ca","version":5,"debugenabled":false,"domain":"notify","service":"","areaId":[],"deviceId":[],"entityId":[],"data":"","dataType":"json","mergeContext":"callServiceData","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":830,"y":80,"wires":[[]]},{"id":"6fdf5748e207aa7e","type":"function","z":"6dc0247c.d7210c","name":"create CLEAR service call","func":"msg._originalPayload = msg.payload;\nflow.set('latestMessage', msg);\n\nvar clearAll = false;\nvar services = \"\";\n\nif (typeof msg.notificationOverride !== 'undefined') {\n if (typeof msg.notificationOverride.clear !== 'undefined' && msg.notificationOverride.clear !== null && msg.notificationOverride.clear) {\n clearAll = true;\n }\n \n if (typeof msg.notificationOverride.services !== 'undefined' && msg.notificationOverride.services !== null && msg.notificationOverride.services){\n services = msg.notificationOverride.services;\n } else {\n services = flow.get('service');\n }\n} else {\n services = flow.get('service');\n}\n\nif(!services) {\n node.status({\n text: 'no services defined',\n shape: 'ring',\n fill: 'red'\n });\n return; \n}\n\n// create ios msg object\n\nmsg.payload = {\n domain: 'notify',\n data: {\n message: \"clear_notification\",\n data: {\n tag: flow.get('tag'),\n }\n }\n };\n\nfunction getPrettyDate() {\n return new Date().toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n hour12: false,\n hour: 'numeric',\n minute: 'numeric',\n });\n}\n\nif (clearAll){\n delete msg.notificationOverride;\n}\n \nvar xCountCleared = 0;\nservices.trim().split(/,\\s*/).forEach(service => {\n if(!service) return;\n // only clear on devices that didn't send the event.\n \n if (clearAll){\n msg.payload.service = service;\n node.send(msg);\n xCountCleared++;\n } else if (!service.includes(msg._originalPayload.event.sourceDeviceID)){\n msg.payload.service = service;\n node.send(msg);\n xCountCleared++;\n }\n});\nif (xCountCleared > 0) {\n node.status({\n text: `${xCountCleared} messages cleared at: ${getPrettyDate()}`,\n shape: 'dot',\n fill: 'blue'\n });\n} else {\n node.status({\n text: `No messages cleared: ${getPrettyDate()}`,\n shape: 'dot',\n fill: 'red'\n });\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":750,"y":220,"wires":[["05b8370d35105d3c"]]},{"id":"a69ed312811b3a6d","type":"switch","z":"6dc0247c.d7210c","name":"Clear Notification on Action?","property":"isClearNotificationsOnAction","propertyType":"env","rules":[{"t":"true"},{"t":"false"}],"checkall":"true","repair":false,"outputs":2,"x":460,"y":320,"wires":[["6fdf5748e207aa7e","227a6ab8de989095"],["c25a82298fbaad78"]]},{"id":"e229e2d8efb85d22","type":"api-call-service","z":"6dc0247c.d7210c","name":"Clear Notifications","server":"296c0678.b5f9ca","version":5,"debugenabled":false,"domain":"notify","service":"","areaId":[],"deviceId":[],"entityId":[],"data":"","dataType":"json","mergeContext":"callServiceData","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1190,"y":140,"wires":[[]]},{"id":"227a6ab8de989095","type":"delay","z":"6dc0247c.d7210c","name":"","pauseType":"delay","timeout":"10","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"outputs":1,"x":720,"y":320,"wires":[["c25a82298fbaad78"]]},{"id":"6b940f2bfba5188c","type":"switch","z":"6dc0247c.d7210c","name":"clear?","property":"notificationOverride.clear","propertyType":"msg","rules":[{"t":"istype","v":"undefined","vt":"undefined"},{"t":"null"},{"t":"false"},{"t":"true"}],"checkall":"false","repair":false,"outputs":4,"x":210,"y":80,"wires":[["3586791854cfef41"],["3586791854cfef41"],["3586791854cfef41"],["6fdf5748e207aa7e"]]},{"id":"05b8370d35105d3c","type":"delay","z":"6dc0247c.d7210c","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"outputs":1,"x":970,"y":160,"wires":[["e229e2d8efb85d22"]]},{"id":"84115d3979a0b0b6","type":"delay","z":"6dc0247c.d7210c","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"outputs":1,"x":630,"y":80,"wires":[["fcf9f9c27469a607"]]},{"id":"296c0678.b5f9ca","type":"server","name":"Home Assistant","version":5,"addon":true,"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":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]
I’m not sure what to update in order to get those working again, though. I get the impression it has something to do with this .replace
in the build message
function node:
const index = [1,2,3,4].find(i => env.get(`action${i}Title`).replace(/[^\w\s]/gi, '').replace(/\s+/g,'_').toUpperCase() === event.actionName);
flow.set("responseIndex",index);
node.status({
text: `${env.get(`action${index}Title`).replace(/[^\w\s]/gi, '').replace(/\s+/g,'_').toUpperCase()} at: ${getPrettyDate()}`,
shape: 'dot',
fill: 'green'
});
EDIT: It looks like the subflow is still working for the most part, but I’m getting warn debug messages every time they run.