Sentence
The Sentence node is triggered when the Home Assistant Assist feature matches a sentence from a voice assistant using the default conversation agent. This node enables voice control integrations, allowing specific voice commands to trigger automations within Node-RED.
Sentences support basic template syntax. Refer to the Home Assistant documentation for more details.
Warning
This node requires the Custom Integration to be installed in Home Assistant.
Configuration Options
Mode
- Type:
string
- Options:
trigger
response
Defines the node’s function.
If set to trigger, the node activates when a sentence is matched.
If set to response, the node sends a dynamic response back to Home Assistant.
Sentences
- Type:
string
A list of sentences to match. Supports basic template syntax. For more details, see the Home Assistant documentation.
Response Type
- Type:
string
- Options:
dynamic
fixed
Specifies the type of response sent to Home Assistant:
- Fixed: The same response is sent for all matched sentences.
- Dynamic: The response is determined by the node set to response mode.
Response
- Type:
string
The message sent to Home Assistant when a sentence is matched. This option is used only if the Response Type is set to fixed
.
Fallback Response
- Type:
string
The message sent to Home Assistant when a timeout occurs. This is used when the Response Type is set to dynamic
.
Response Timeout
- Type:
number
Specifies the time in milliseconds to wait for a response before sending the Fallback Response. This option is used only when the Response Type is set to dynamic
.
Expose As
- Type:
string
Select an entity to create a switch in Home Assistant. Turning the switch on or off will enable or disable this node in Node-RED.
Inputs
All properties must be provided in msg.payload
.
Example input:
{
"response": "The light is now on"
}
Response
- Type:
string
The response sent to Home Assistant when a sentence is matched. This is used only when the Response Type is set to dynamic
.
Outputs
Value types:
trigger id
: The sentence that triggered the flow.config
: The node's configuration properties.
Examples
Basic Usage
[{"id":"2f10cb78ab2f486f","type":"debug","z":"01b6599a0739a237","name":"debug","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"msg","x":418,"y":1136,"wires":[]},{"id":"5c563c29d19f4aab","type":"ha-sentence","z":"01b6599a0739a237","name":"","server":"5d205f70b1e41e9f","version":2,"inputs":0,"outputs":1,"exposeAsEntityConfig":"","mode":"trigger","sentences":["[it's ]party time","happy (new year|birthday)","hello world"],"response":"","responseType":"fixed","responseTimeout":1000,"outputProperties":[{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"},{"property":"payload","propertyType":"msg","value":"","valueType":"triggerId"},{"property":"sentences","propertyType":"msg","value":"sentences","valueType":"config"}],"x":212,"y":1136,"wires":[["2f10cb78ab2f486f"]]},{"id":"4868b36e0e57db4f","type":"api-call-service","z":"01b6599a0739a237","name":"process sentence","server":"","version":7,"debugenabled":false,"action":"conversation.process","floorId":[],"areaId":[],"deviceId":[],"entityId":[],"labelId":[],"data":" {\"text\": payload}\t","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","blockInputOverrides":false,"domain":"conversation","service":"process","x":458,"y":1088,"wires":[[]]},{"id":"0bd711e6ab321cf9","type":"inject","z":"01b6599a0739a237","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"happy new year","payloadType":"str","x":236,"y":1088,"wires":[["4868b36e0e57db4f"]]},{"id":"7b19f1bcd79bf7ea","type":"inject","z":"01b6599a0739a237","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"happy birthday","payloadType":"str","x":240,"y":1040,"wires":[["4868b36e0e57db4f"]]},{"id":"fdec3314ea56130d","type":"inject","z":"01b6599a0739a237","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"party time","payloadType":"str","x":220,"y":992,"wires":[["4868b36e0e57db4f"]]},{"id":"92aa9c7e046ebba3","type":"inject","z":"01b6599a0739a237","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"it's party time","payloadType":"str","x":234,"y":944,"wires":[["4868b36e0e57db4f"]]},{"id":"4c1ecc1396d9eddf","type":"inject","z":"01b6599a0739a237","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"hello world","payloadType":"str","x":224,"y":896,"wires":[["4868b36e0e57db4f"]]}]
Dynamic Response Examples
Example 1: Count Lights On and Off
This example shows how to use the Sentence node to provide a dynamic response based on the number of lights that are on or off in the house. It also turns on any lights that were off.
[{"id":"5b44e487c5795df9","type":"ha-get-entities","z":"c89d915bdff0f798","name":"lights off count","server":"","version":1,"rules":[{"condition":"state_object","property":"entity_id","logic":"starts_with","value":"light.","valueType":"str"},{"condition":"state_object","property":"state","logic":"is","value":"off","valueType":"str"}],"outputType":"array","outputEmptyResults":true,"outputLocationType":"msg","outputLocation":"lightsOff","outputResultsCount":1,"x":512,"y":1136,"wires":[["99c90d5fd17832c9","7c588d1510201532"]]},{"id":"99c90d5fd17832c9","type":"ha-get-entities","z":"c89d915bdff0f798","name":"lights on count","server":"","version":1,"rules":[{"condition":"state_object","property":"entity_id","logic":"starts_with","value":"light.","valueType":"str"},{"condition":"state_object","property":"state","logic":"is","value":"on","valueType":"str"}],"outputType":"count","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"lightsOnCount","outputResultsCount":1,"x":704,"y":1136,"wires":[["f6e701c97c731979"]]},{"id":"09cb88520209e712","type":"inject","z":"c89d915bdff0f798","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":332,"y":1088,"wires":[["0b2ef68df13c5b94"]]},{"id":"0b2ef68df13c5b94","type":"api-call-service","z":"c89d915bdff0f798","name":"","server":"","version":7,"debugenabled":false,"action":"conversation.process","floorId":[],"areaId":[],"deviceId":[],"entityId":[],"labelId":[],"data":"{\"text\": \"let there be light\"}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"queue":"none","blockInputOverrides":true,"domain":"conversation","service":"process","x":532,"y":1088,"wires":[["edfa883350eca925"]]},{"id":"edfa883350eca925","type":"debug","z":"c89d915bdff0f798","name":"output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.response.speech.plain.speech","targetType":"msg","statusVal":"","statusType":"auto","x":886,"y":1088,"wires":[]},{"id":"b389cf7e343fc938","type":"api-call-service","z":"c89d915bdff0f798","name":"","server":"","version":7,"debugenabled":false,"action":"light.turn_on","floorId":[],"areaId":[],"deviceId":[],"entityId":[],"labelId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","blockInputOverrides":true,"domain":"light","service":"turn_on","x":1090,"y":1184,"wires":[[]]},{"id":"28191039a0c43c00","type":"change","z":"c89d915bdff0f798","name":"build entity list","rules":[{"t":"set","p":"payload","pt":"msg","to":"{ \"target\": { \"entity_id\": lightsOff.entity_id}}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":910,"y":1184,"wires":[["b389cf7e343fc938"]]},{"id":"794a0664ef0e9ab0","type":"ha-sentence","z":"c89d915bdff0f798","name":"let there be light","server":"2dad33ee.42bf5c","version":2,"inputs":1,"outputs":1,"exposeAsEntityConfig":"","mode":"response","sentences":["let there be light"],"response":"","responseType":"str","triggerResponse":"","triggerResponseType":"dynamic","responseTimeout":1000,"outputProperties":[{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"},{"property":"payload","propertyType":"msg","value":"","valueType":"triggerId"}],"x":328,"y":1136,"wires":[["5b44e487c5795df9"]]},{"id":"f6e701c97c731979","type":"ha-sentence","z":"c89d915bdff0f798","name":"","server":"2dad33ee.42bf5c","version":2,"inputs":1,"outputs":1,"exposeAsEntityConfig":"","mode":"response","sentences":[],"response":"lightsOnCount & \" lights were already on turning on \" & $count(lightsOffCount) & \" lights that were off\"\t","responseType":"jsonata","triggerResponse":"","triggerResponseType":"fixed","responseTimeout":1000,"outputProperties":[],"x":892,"y":1136,"wires":[[]]},{"id":"7c588d1510201532","type":"switch","z":"c89d915bdff0f798","name":"any lights off?","property":"lightsOff.length","propertyType":"msg","rules":[{"t":"gt","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":706,"y":1184,"wires":[["28191039a0c43c00"]]}]
Example 2: Check Garage Sensor
This example checks the status of a binary sensor to determine whether the car is in the garage. If the car is present, a response is sent confirming its location. If the car is not present, the response states that the car is not in the garage.
[{"id":"d140cd86c26cbbe5","type":"inject","z":"01b6599a0739a237","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":204,"y":960,"wires":[["c18458aa0fda5201"]]},{"id":"c18458aa0fda5201","type":"api-call-service","z":"01b6599a0739a237","name":"is the car in the garage","server":"","version":7,"debugenabled":false,"action":"conversation.process","floorId":[],"areaId":[],"deviceId":[],"entityId":[],"labelId":[],"data":"{\"text\": \"is the car in the garage\"}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"queue":"none","blockInputOverrides":true,"domain":"conversation","service":"process","x":462,"y":960,"wires":[["080f0fda9ce2ebc9"]]},{"id":"080f0fda9ce2ebc9","type":"debug","z":"01b6599a0739a237","name":"output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.response.speech.plain.speech","targetType":"msg","statusVal":"","statusType":"auto","x":674,"y":960,"wires":[]},{"id":"aac0b36dca0c47b4","type":"ha-sentence","z":"01b6599a0739a237","name":"is the car in the garage","server":"5d205f70b1e41e9f","version":2,"inputs":0,"outputs":1,"exposeAsEntityConfig":"","mode":"trigger","sentences":["is the car in the garage"],"response":"Something took to long","responseType":"jsonata","triggerResponseType":"dynamic","responseTimeout":1000,"outputProperties":[{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"},{"property":"payload","propertyType":"msg","value":"","valueType":"triggerId"}],"x":220,"y":1008,"wires":[["6a2a0e27afac616e"]]},{"id":"2dd86795094ba553","type":"ha-sentence","z":"01b6599a0739a237","name":"","server":"5d205f70b1e41e9f","version":2,"inputs":1,"outputs":1,"exposeAsEntityConfig":"","mode":"response","sentences":[],"response":"payload","responseType":"msg","triggerResponseType":"fixed","responseTimeout":1000,"outputProperties":[],"x":940,"y":1008,"wires":[[]]},{"id":"6a2a0e27afac616e","type":"api-current-state","z":"01b6599a0739a237","name":"","server":"","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"binary_sensor.car_in_garage","state_type":"str","blockInputOverrides":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":522,"y":1008,"wires":[["fa724a7fe743faaa"],["30171db069e062f0"]]},{"id":"fa724a7fe743faaa","type":"change","z":"01b6599a0739a237","name":"yes","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"response\": \"Yes the car is in the garage\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":770,"y":1008,"wires":[["2dd86795094ba553"]]},{"id":"30171db069e062f0","type":"change","z":"01b6599a0739a237","name":"no","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"response\": \"No the car is not in the garage\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":772,"y":1056,"wires":[["2dd86795094ba553"]]},{"id":"b4d9680db1056a02","type":"inject","z":"01b6599a0739a237","name":"set car in garage","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":224,"y":1056,"wires":[["0c940aece619684d"]]},{"id":"0c940aece619684d","type":"ha-binary-sensor","z":"01b6599a0739a237","name":"","entityConfig":"c9ce588e6f25ce5d","version":0,"state":"payload","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":496,"y":1056,"wires":[[]]},{"id":"763df26767e56a92","type":"inject","z":"01b6599a0739a237","name":"remove car from garage","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"false","payloadType":"bool","x":254,"y":1104,"wires":[["0c940aece619684d"]]},{"id":"c9ce588e6f25ce5d","type":"ha-entity-config","server":"5d205f70b1e41e9f","deviceConfig":"","name":"car in garage","version":"6","entityType":"binary_sensor","haConfig":[{"property":"name","value":"car in garage"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""}],"resend":true,"debugEnabled":false}]
Example 3: Play a Jellyfin Show
This example demonstrates how to use the Sentence node with Home Assistant's conversation integration to play a show from Jellyfin. The flow utilizes dynamic responses to respond with the selected episode.
Full details can be found in the Cookbook.
[{"id":"13b4618a99045b71","type":"ha-sentence","z":"d728cb91f51ff055","name":"random MASH episode","server":"2dad33ee.42bf5c","version":2,"inputs":0,"outputs":1,"exposeAsEntityConfig":"","mode":"trigger","sentences":["play [a] [random] mash (episode|show)"],"response":"","responseType":"str","triggerResponse":"Something went wrong","triggerResponseType":"dynamic","responseTimeout":"2000","outputProperties":[{"property":"seriesId","propertyType":"msg","value":"3b264a3b9e602ddc9c9a00a343dd5ce2","valueType":"str"},{"property":"deviceId","propertyType":"msg","value":"c76c8695549b5bedfc21f48b0664b8329ed2ebde","valueType":"str"}],"x":124,"y":144,"wires":[["45d8457d15bfa505"]]},{"id":"41a351cf86e6a70e","type":"random-item","z":"d728cb91f51ff055","name":"","input":"mash_episodes","inputType":"flow","output":"payload","outputType":"msg","number":1,"x":502,"y":144,"wires":[["7de8f9a16179ad63"]]},{"id":"04f10897f711e88c","type":"change","z":"d728cb91f51ff055","name":"set item id","rules":[{"t":"set","p":"_itemId","pt":"msg","to":"payload.id","tot":"msg","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":850,"y":144,"wires":[["a29f9d7e6a746a9e"]]},{"id":"a29f9d7e6a746a9e","type":"openApi-red","z":"d728cb91f51ff055","name":"","configUrlNode":"9435086ff9117a76","apiTag":"Session","keepAuth":true,"operationData":{"id":"GetSessions","hasOperationId":true,"path":"/Sessions","method":"get"},"outputStyle":"each response","errorHandling":"throw exception","internalErrors":{"text":"","source":""},"parameters":{"controllableByUserId query":{"name":"controllableByUserId","type":"jsonata","value":"$env(\"userId\")","in":"query"},"deviceId query":{"name":"deviceId","isActive":true,"type":"msg","value":"deviceId","in":"query"},"activeWithinSeconds query":{"name":"activeWithinSeconds","in":"query"}},"requestContentType":"application/json","responseContentType":"application/json","outputs":3,"responseOutputLabels":[{"code":"200","text":"List of sessions returned."},{"code":"401","text":"Unauthorized"},{"code":"403","text":"Forbidden"}],"responseAsPayload":false,"debugMode":"","headers":[],"_version":"2.1.0","x":1010,"y":144,"wires":[["13987ef9a8e0286f"],[],[]]},{"id":"13987ef9a8e0286f","type":"openApi-red","z":"d728cb91f51ff055","name":"","configUrlNode":"9435086ff9117a76","apiTag":"Session","keepAuth":true,"operationData":{"id":"Play","hasOperationId":true,"path":"/Sessions/{sessionId}/Playing","method":"post"},"outputStyle":"each response","errorHandling":"throw exception","internalErrors":{"text":"","source":""},"parameters":{"itemIds query":{"name":"itemIds","isActive":true,"required":true,"type":"msg","value":"_itemId","in":"query"},"playCommand query":{"name":"playCommand","isActive":true,"required":true,"type":"select","value":"PlayNow","in":"query"},"sessionId path":{"name":"sessionId","isActive":true,"required":true,"type":"msg","value":"payload.0.Id","in":"path"},"startPositionTicks query":{"name":"startPositionTicks","in":"query"},"mediaSourceId query":{"name":"mediaSourceId","in":"query"},"audioStreamIndex query":{"name":"audioStreamIndex","in":"query"},"subtitleStreamIndex query":{"name":"subtitleStreamIndex","in":"query"},"startIndex query":{"name":"startIndex","in":"query"}},"requestContentType":"application/json","responseContentType":"","outputs":3,"responseOutputLabels":[{"code":"204","text":"Instruction sent to session."},{"code":"401","text":"Unauthorized"},{"code":"403","text":"Forbidden"}],"responseAsPayload":false,"debugMode":false,"headers":[],"_version":"2.1.0","x":1146,"y":144,"wires":[["e47af5331f32c92d"],[],[]]},{"id":"b907d1659b1fb6cc","type":"openApi-red","z":"d728cb91f51ff055","name":"","configUrlNode":"9435086ff9117a76","apiTag":"Session","keepAuth":true,"operationData":{"id":"GetSessions","hasOperationId":true,"path":"/Sessions","method":"get"},"outputStyle":"each response","errorHandling":"throw exception","internalErrors":{"text":"","source":""},"parameters":{"controllableByUserId query":{"name":"controllableByUserId","type":"jsonata","value":"$env(\"userId\")","in":"query"},"deviceId query":{"name":"deviceId","type":"msg","value":"deviceId","in":"query"},"activeWithinSeconds query":{"name":"activeWithinSeconds","in":"query"}},"requestContentType":"application/json","responseContentType":"application/json","outputs":3,"responseOutputLabels":[{"code":"200","text":"List of sessions returned."},{"code":"401","text":"Unauthorized"},{"code":"403","text":"Forbidden"}],"responseAsPayload":false,"debugMode":"","headers":[],"_version":"2.1.0","x":302,"y":354,"wires":[["21244d4a0ab99de7"],[],[]]},{"id":"47b0ace1ee8cc84e","type":"inject","z":"d728cb91f51ff055","name":"Find device ID","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":115,"y":351,"wires":[["b907d1659b1fb6cc"]]},{"id":"21244d4a0ab99de7","type":"debug","z":"d728cb91f51ff055","name":"devices","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload {DeviceName: $.{\"client\": Client, \"deviceId\": DeviceId}}","targetType":"jsonata","statusVal":"","statusType":"auto","x":468,"y":354,"wires":[]},{"id":"e47af5331f32c92d","type":"ha-sentence","z":"d728cb91f51ff055","name":"send response back to HA","server":"2dad33ee.42bf5c","version":2,"inputs":1,"outputs":1,"exposeAsEntityConfig":"","mode":"response","sentences":["play [a] random mash episode"],"response":"_response","responseType":"msg","triggerResponse":"Something went wrong","triggerResponseType":"dynamic","responseTimeout":1000,"outputProperties":[],"x":1050,"y":192,"wires":[[]]},{"id":"7de8f9a16179ad63","type":"template","z":"d728cb91f51ff055","name":"format response","field":"_response","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"Playing MASH {{payload.seasonName}} Episode {{payload.episodeNumber}}, {{{payload.episodeName}}}","output":"str","x":680,"y":144,"wires":[["04f10897f711e88c"]]},{"id":"d050c8425ac14d8b","type":"openApi-red","z":"d728cb91f51ff055","name":"","configUrlNode":"9435086ff9117a76","apiTag":"Search","keepAuth":true,"operationData":{"id":"GetSearchHints","hasOperationId":true,"path":"/Search/Hints","method":"get"},"outputStyle":"each response","errorHandling":"throw exception","internalErrors":{"text":"","source":""},"parameters":{"searchTerm query":{"name":"searchTerm","isActive":true,"required":true,"type":"str","value":"M*A*S*H","in":"query"},"startIndex query":{"name":"startIndex","in":"query"},"limit query":{"name":"limit","in":"query"},"userId query":{"name":"userId","in":"query"},"includeItemTypes query":{"name":"includeItemTypes","in":"query"},"excludeItemTypes query":{"name":"excludeItemTypes","in":"query"},"mediaTypes query":{"name":"mediaTypes","in":"query"},"parentId query":{"name":"parentId","in":"query"},"isMovie query":{"name":"isMovie","in":"query"},"isSeries query":{"name":"isSeries","in":"query"},"isNews query":{"name":"isNews","in":"query"},"isKids query":{"name":"isKids","in":"query"},"isSports query":{"name":"isSports","in":"query"},"includePeople query":{"name":"includePeople","in":"query"},"includeMedia query":{"name":"includeMedia","in":"query"},"includeGenres query":{"name":"includeGenres","in":"query"},"includeStudios query":{"name":"includeStudios","in":"query"},"includeArtists query":{"name":"includeArtists","in":"query"}},"requestContentType":"application/json","responseContentType":"application/json","outputs":3,"responseOutputLabels":[{"code":"200","text":"Search hint returned."},{"code":"401","text":"Unauthorized"},{"code":"403","text":"Forbidden"}],"responseAsPayload":false,"debugMode":"","headers":[],"_version":"2.1.0","x":308,"y":451,"wires":[["63e5998dd3c9dba0"],[],[]]},{"id":"87d85ce4c11270d6","type":"inject","z":"d728cb91f51ff055","name":"Find series ID","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":111,"y":448,"wires":[["d050c8425ac14d8b"]]},{"id":"63e5998dd3c9dba0","type":"debug","z":"d728cb91f51ff055","name":"results","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.SearchHints {Name: $.{\"seriesId\": Id, \"series\": Series, \"year\": ProductionYear, \"type\": Type}}","targetType":"jsonata","statusVal":"","statusType":"auto","x":466,"y":451,"wires":[]},{"id":"e286325a4e63d372","type":"openApi-red","z":"d728cb91f51ff055","name":"get series episodes","configUrlNode":"9435086ff9117a76","apiTag":"Items","keepAuth":true,"operationData":{"id":"GetItems","hasOperationId":true,"path":"/Items","method":"get"},"outputStyle":"each response","errorHandling":"throw exception","internalErrors":{"text":"","source":""},"parameters":{"userId query":{"name":"userId","isActive":true,"type":"jsonata","value":"$env(\"userId\")","in":"query"},"maxOfficialRating query":{"name":"maxOfficialRating","in":"query"},"hasThemeSong query":{"name":"hasThemeSong","in":"query"},"hasThemeVideo query":{"name":"hasThemeVideo","in":"query"},"hasSubtitles query":{"name":"hasSubtitles","in":"query"},"hasSpecialFeature query":{"name":"hasSpecialFeature","in":"query"},"hasTrailer query":{"name":"hasTrailer","in":"query"},"adjacentTo query":{"name":"adjacentTo","in":"query"},"parentIndexNumber query":{"name":"parentIndexNumber","in":"query"},"hasParentalRating query":{"name":"hasParentalRating","in":"query"},"isHd query":{"name":"isHd","in":"query"},"is4K query":{"name":"is4K","in":"query"},"locationTypes query":{"name":"locationTypes","in":"query"},"excludeLocationTypes query":{"name":"excludeLocationTypes","in":"query"},"isMissing query":{"name":"isMissing","in":"query"},"isUnaired query":{"name":"isUnaired","in":"query"},"minCommunityRating query":{"name":"minCommunityRating","in":"query"},"minCriticRating query":{"name":"minCriticRating","in":"query"},"minPremiereDate query":{"name":"minPremiereDate","in":"query"},"minDateLastSaved query":{"name":"minDateLastSaved","in":"query"},"minDateLastSavedForUser query":{"name":"minDateLastSavedForUser","in":"query"},"maxPremiereDate query":{"name":"maxPremiereDate","in":"query"},"hasOverview query":{"name":"hasOverview","in":"query"},"hasImdbId query":{"name":"hasImdbId","in":"query"},"hasTmdbId query":{"name":"hasTmdbId","in":"query"},"hasTvdbId query":{"name":"hasTvdbId","in":"query"},"isMovie query":{"name":"isMovie","type":"bool","value":"true","in":"query"},"isSeries query":{"name":"isSeries","in":"query"},"isNews query":{"name":"isNews","in":"query"},"isKids query":{"name":"isKids","in":"query"},"isSports query":{"name":"isSports","in":"query"},"excludeItemIds query":{"name":"excludeItemIds","in":"query"},"startIndex query":{"name":"startIndex","in":"query"},"limit query":{"name":"limit","type":"num","value":"1","in":"query"},"recursive query":{"name":"recursive","isActive":true,"type":"bool","value":"true","in":"query"},"searchTerm query":{"name":"searchTerm","in":"query"},"sortOrder query":{"name":"sortOrder","type":"str","collapsed":false,"value":"Descending","in":"query"},"parentId query":{"name":"parentId","isActive":true,"type":"msg","value":"seriesId","in":"query"},"fields query":{"name":"fields","in":"query"},"excludeItemTypes query":{"name":"excludeItemTypes","in":"query"},"includeItemTypes query":{"name":"includeItemTypes","isActive":true,"type":"str","value":"Episode","in":"query"},"filters query":{"name":"filters","in":"query"},"isFavorite query":{"name":"isFavorite","in":"query"},"mediaTypes query":{"name":"mediaTypes","in":"query"},"imageTypes query":{"name":"imageTypes","in":"query"},"sortBy query":{"name":"sortBy","type":"str","value":"DatePlayed","in":"query"},"isPlayed query":{"name":"isPlayed","in":"query"},"genres query":{"name":"genres","in":"query"},"officialRatings query":{"name":"officialRatings","in":"query"},"tags query":{"name":"tags","in":"query"},"years query":{"name":"years","in":"query"},"enableUserData query":{"name":"enableUserData","in":"query"},"imageTypeLimit query":{"name":"imageTypeLimit","in":"query"},"enableImageTypes query":{"name":"enableImageTypes","in":"query"},"person query":{"name":"person","in":"query"},"personIds query":{"name":"personIds","in":"query"},"personTypes query":{"name":"personTypes","in":"query"},"studios query":{"name":"studios","in":"query"},"artists query":{"name":"artists","in":"query"},"excludeArtistIds query":{"name":"excludeArtistIds","in":"query"},"artistIds query":{"name":"artistIds","in":"query"},"albumArtistIds query":{"name":"albumArtistIds","in":"query"},"contributingArtistIds query":{"name":"contributingArtistIds","in":"query"},"albums query":{"name":"albums","in":"query"},"albumIds query":{"name":"albumIds","in":"query"},"ids query":{"name":"ids","in":"query"},"videoTypes query":{"name":"videoTypes","in":"query"},"minOfficialRating query":{"name":"minOfficialRating","in":"query"},"isLocked query":{"name":"isLocked","in":"query"},"isPlaceHolder query":{"name":"isPlaceHolder","in":"query"},"hasOfficialRating query":{"name":"hasOfficialRating","in":"query"},"collapseBoxSetItems query":{"name":"collapseBoxSetItems","in":"query"},"minWidth query":{"name":"minWidth","in":"query"},"minHeight query":{"name":"minHeight","in":"query"},"maxWidth query":{"name":"maxWidth","in":"query"},"maxHeight query":{"name":"maxHeight","in":"query"},"is3D query":{"name":"is3D","in":"query"},"seriesStatus query":{"name":"seriesStatus","in":"query"},"nameStartsWithOrGreater query":{"name":"nameStartsWithOrGreater","in":"query"},"nameStartsWith query":{"name":"nameStartsWith","in":"query"},"nameLessThan query":{"name":"nameLessThan","in":"query"},"studioIds query":{"name":"studioIds","in":"query"},"genreIds query":{"name":"genreIds","in":"query"},"enableTotalRecordCount query":{"name":"enableTotalRecordCount","in":"query"},"enableImages query":{"name":"enableImages","in":"query"}},"requestContentType":"application/json","responseContentType":"application/json","outputs":3,"responseOutputLabels":[{"code":"200","text":"Success"},{"code":"401","text":"Unauthorized"},{"code":"403","text":"Forbidden"}],"responseAsPayload":false,"debugMode":false,"headers":[],"_version":"2.1.0","x":546,"y":290,"wires":[["57dccb79c1e6b527"],[],[]]},{"id":"57dccb79c1e6b527","type":"function","z":"d728cb91f51ff055","name":"store episodes in flow context","func":"const episodes = flow.get(\"mash_episodes\") ?? [];\n// only keep the data we need\nmsg.payload.Items.forEach((e) => {\n episodes.push({\n id: e.Id,\n episodeNumber: e.IndexNumber,\n seasonName: e.SeasonName,\n episodeName: e.Name,\n }) \n});\nflow.set(\"mash_episodes\", episodes);\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":794,"y":290,"wires":[["b195cd17f0d831f6"]]},{"id":"b195cd17f0d831f6","type":"link out","z":"d728cb91f51ff055","name":"","mode":"return","links":[],"x":973,"y":290,"wires":[]},{"id":"956492fb58071a3f","type":"link in","z":"d728cb91f51ff055","name":"get episodes","links":[],"x":94,"y":290,"wires":[["ae47bac31c4abf22"]],"l":true},{"id":"45d8457d15bfa505","type":"link call","z":"d728cb91f51ff055","name":"get episodes","links":["956492fb58071a3f"],"linkType":"static","timeout":"30","x":330,"y":144,"wires":[["41a351cf86e6a70e"]]},{"id":"cf88a7b5365c7c0f","type":"ha-sentence","z":"d728cb91f51ff055","name":"play MASH episode","server":"2dad33ee.42bf5c","version":2,"inputs":0,"outputs":1,"exposeAsEntityConfig":"","mode":"trigger","sentences":["play mash season {season} episode {episode}","play mash episode {episode}"],"response":"","responseType":"str","triggerResponse":"Something went wrong","triggerResponseType":"dynamic","responseTimeout":"2000","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"},{"property":"deviceId","propertyType":"msg","value":"c76c8695549b5bedfc21f48b0664b8329ed2ebde","valueType":"str"},{"property":"seriesId","propertyType":"msg","value":"3b264a3b9e602ddc9c9a00a343dd5ce2","valueType":"str"}],"x":114,"y":192,"wires":[["3936fa1204b55b3f"]]},{"id":"ae47bac31c4abf22","type":"switch","z":"d728cb91f51ff055","name":"have episode list?","property":"mash_episodes","propertyType":"flow","rules":[{"t":"empty"},{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":3,"x":326,"y":290,"wires":[["e286325a4e63d372"],["e286325a4e63d372"],["b195cd17f0d831f6"]]},{"id":"a87cff07f2f77174","type":"function","z":"d728cb91f51ff055","name":"find episode","func":"const episodes = flow.get(\"mash_episodes\") ?? [];\nconst episode = convertStringToNumber(msg.payload.entities.episode.value);\nconst season = convertStringToNumber(msg.payload.entities.season?.value);\n\nif (season) {\n msg.payload = episodes.find(e => e.episodeNumber === episode && e.seasonName === `Season ${season}`);\n} else { // if season is empty find show by number is aired in series\n msg.payload = findNthShowAired(episodes, episode);\n}\n\n// episode not found\nif (!msg.payload) {\n msg._response = `No episode found for MASH ${season ? `Season ${season}` : ''} Episode ${episode}`;\n return [null, msg];\n}\nreturn msg;\n\nfunction findNthShowAired(episodes, nthShow) {\n if (nthShow <= 0 || nthShow > episodes.length) {\n return null; // Invalid input or out of range\n }\n\n // Sort episodes by season and episode number to ensure correct airing order\n const sortedEpisodes = episodes.sort((a, b) => {\n const seasonA = Number(a.seasonName.replace('Season ', ''));\n const seasonB = Number(b.seasonName.replace('Season ', ''));\n\n if (seasonA === seasonB) {\n return a.episodeNumber - b.episodeNumber;\n } else {\n return seasonA - seasonB;\n }\n });\n\n return sortedEpisodes[nthShow - 1]; // nthShow is 1-based, array is 0-based\n}\n\nfunction convertStringToNumber(input) {\n if (input === undefined) return;\n \n const numberWords = {\n 'zero': 0, 'one': 1, 'two': 2, 'three': 3, 'four': 4, \n 'five': 5, 'six': 6, 'seven': 7, 'eight': 8, 'nine': 9, \n 'ten': 10, 'eleven': 11, 'twelve': 12, 'thirteen': 13, \n 'fourteen': 14, 'fifteen': 15, 'sixteen': 16, 'seventeen': 17, \n 'eighteen': 18, 'nineteen': 19, 'twenty': 20\n };\n\n // Check if input is already a numeric string\n if (!isNaN(input)) {\n return Number(input);\n }\n\n // Check if the input is a number word\n const lowerInput = input.toLowerCase().trim();\n if (lowerInput in numberWords) {\n return numberWords[lowerInput];\n }\n}","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":502,"y":192,"wires":[["7de8f9a16179ad63"],["e47af5331f32c92d"]]},{"id":"3936fa1204b55b3f","type":"link call","z":"d728cb91f51ff055","name":"get episodes","links":["956492fb58071a3f"],"linkType":"static","timeout":"30","x":330,"y":192,"wires":[["a87cff07f2f77174"]]},{"id":"31e71416c0d8fcd4","type":"comment","z":"d728cb91f51ff055","name":"The deviceId and seriesId will need to be changed in the output properties of the sentence node","info":"","x":354,"y":96,"wires":[]},{"id":"dcc480460a475cf8","type":"openApi-red","z":"d728cb91f51ff055","name":"","configUrlNode":"9435086ff9117a76","apiTag":"User","keepAuth":true,"operationData":{"id":"GetPublicUsers","hasOperationId":true,"path":"/Users/Public","method":"get"},"outputStyle":"each response","errorHandling":"throw exception","internalErrors":{"text":"","source":""},"parameters":{},"requestContentType":"application/json","responseContentType":"application/json","outputs":1,"responseOutputLabels":[{"code":"200","text":"Public users returned."}],"responseAsPayload":false,"debugMode":"","headers":[],"_version":"2.1.0","x":312,"y":513,"wires":[["7bfc313b1590bc35"]]},{"id":"3225bc86df87feba","type":"inject","z":"d728cb91f51ff055","name":"Find user ID","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":114,"y":513,"wires":[["dcc480460a475cf8"]]},{"id":"7bfc313b1590bc35","type":"debug","z":"d728cb91f51ff055","name":"results","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload {Name: Id}","targetType":"jsonata","statusVal":"","statusType":"auto","x":470,"y":513,"wires":[]},{"id":"db16886a9eee2c17","type":"comment","z":"d728cb91f51ff055","name":"The user ID will need to be changed in the \"get series episodes\"","info":"","x":686,"y":240,"wires":[]},{"id":"35ebe5b08b627b76","type":"comment","z":"d728cb91f51ff055","name":"Edit searchTerm","info":"","x":308,"y":400,"wires":[]}]