i8beef / node-red-contrib-castv2

MIT License
22 stars 15 forks source link

Media Cast triggers itself when shutting off speaker #36

Closed BertVereecken closed 3 years ago

BertVereecken commented 3 years ago

Hi,

First of all thanks for the amazing lib, it looks very promising.

I have a node-red flow that triggers my Google Nest Audio speaker based on my alarm clock of my phone. That workflow that I have right now: Alarm triggers => trigger Google Cast Node and stream URL of radio station. This works. But of course, when I hit snooze, it will trigger the flow all over again and start playing again. I solved this by first checking what the state is (with GET_STATUS as type). Based on that state, It should or should not start over.

My scenario:

  1. Alarm triggers
  2. Check if something is already playing
  3. If something is playing, do nothing/stop the flow
  4. If nothing is playing, start playing

When I shut down my speaker, it starts playing again. The node triggers itself I guess. This is the shutdown button

Screenshot 2020-10-31 at 15 13 46

This is my workflow: (don't mind the error), i actually check the status with node-red-cast

Screenshot 2020-10-31 at 15 13 10

Thanks for looking into this. Have a good weekend, Bert

i8beef commented 3 years ago

Sorry, having trouble parsing your question... it sounds like your alarm triggers the flow fine, starts playing, but then when you hit snooze when it goes off again 10 minutes later, it triggers again and starts over? If so I'd say you have only a few options:

  1. Figure out how to only trigger on initial alarm instead of snooze events. Depends on whatever is sending the event.
  2. "Debounce" the event so that you can only get one trigger within some time frame (say an hour?). You could use a delay node to rate limit.
  3. Invent your own blocking like you've done.

Either way, this isn't something wrong with the node though, you are sending it multiple cast LOAD's, which of course starts over from the beginning. You have to invent your own blocking here.

Also, just a note, but you the output of this node should always return the current status of the cast target without having to do a GET first... you could just have a function node hanging off the end that STORES the last result in a float variable that you check instead of doing the GET and evaluation you are doing I think...

Another note, mixing and matching this node with node-red-contrib-cast MIGHT not be a good idea. That node's handling of cast sessions is COMPLETELY different, and I think it might completely kill the existing sessions on most commands. If you're having problems with that check in your flow "stopping" the active cast, its likely not this node, but that one.

BertVereecken commented 3 years ago

Hi Thanks for the fast reply.

Ok, let's forget for a moment about the example I gave with my alarm.

Imagine the following flow underneath and imagine that the "inject" node is my alarm triggering. The first time you trigger/click it, the flow does its thing and the speakers starts playing correctly.

Now I should implement something that checks the current status first before triggering again. Underneath you can see, I have it partly working. When a message does not have a payload, what should I do then ? Because when you click/trigger the "inject" node again (eg. my alarm triggers again), the current streams gets stopped and starts again. How would I do that ?

[{"id":"43956017.b2615","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"25407c9a.f47174","type":"function","z":"43956017.b2615","name":"Inject payload","func":"msg.payload = {\n app: \"DefaultMediaReceiver\",\n type: \"MEDIA\",\n media: {\n url: \"http://icecast.vrtcdn.be/mnm-high.mp3\",\n contentType: \"audio/mp3\",\n streamType: \"BUFFERED\",\n }\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1200,"y":420,"wires":[["442ef184.e457a"]]},{"id":"442ef184.e457a","type":"castv2-sender","z":"43956017.b2615","name":"Nest Audio Bureau","connection":"fbdfc558.9e8328","spotifyAccessToken":"","spotifyAccessTokenExpiration":"","spotifyDeviceName":"","x":1410,"y":420,"wires":[["d047fcdf.58131"]]},{"id":"d9a52f20.84eed","type":"debug","z":"43956017.b2615","name":"after first function","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1950,"y":420,"wires":[]},{"id":"92b4a633.4969c8","type":"inject","z":"43956017.b2615","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1020,"y":420,"wires":[["25407c9a.f47174"]]},{"id":"d047fcdf.58131","type":"function","z":"43956017.b2615","name":"Determine if it should play or not ?","func":"if (msg.payload && msg.payload.playerState) {\n \n var playerState = msg.payload.playerState;\n \n if (playerState === 'PLAYING' || playerState ==='IDLE' || playerState === 'BUFFERING') {\n msg.shouldPlay = false;\n } else {\n msg.shouldPlay = true;\n }\n \n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1680,"y":420,"wires":[["d9a52f20.84eed"]]},{"id":"fbdfc558.9e8328","type":"castv2-connection","z":"","name":"Nest Audio Bureau","target":"Nest Audio Bureau","host":"192.168.0.105","port":"8009"}]

Thanks again for looking into this. Bert

i8beef commented 3 years ago

You can do it the way you're doing it in this flow, but you want to set a FLOW variable, not a property on the msg, and then CHECK that in the "build payload" function node to determine if it should continue executing or not.

You could use flow.set("shouldPlay", false) and then check it in that first function node with

let shouldPlay = flow.get("shouldPlay");
if (!shouldPlay) {
    return null;
}

Which should short circuit the flow.

BertVereecken commented 3 years ago

Thanks for the answer and sorry for my late response

But I didn't know it was possible to set context or flow variables. So thanks for that. I managed to get it working.

This issue can be closed.