Closed psmith3 closed 6 years ago
You can read more about it here
The room name field is referenced like this:
{
"source": "payload",
"name": "data.roomName"
}
and the current playback state is referenced like this:
{
"source": "payload",
"name": "data.state.playbackState"
}
You can read more about trigger rules here
Trigger rule controls when your script will be executed. You basically want to execute your script when room name field is equal to Kitchen
and the playback state is either PLAYING
or STOPPED
.
Translated to the logic you want to define trigger rule: roomName == 'Kitchen' && (playbackState == 'PLAYING' || playbackState == 'STOPPED')
Which in webhook looks like this:
{
"and": [
{
"match": {
"type": "value",
"value": "Kitchen",
"parameter": {
"source": "payload",
"name": "data.roomName"
}
}
},
{
"or": [
{
"match": {
"type": "value",
"value": "PLAYING",
"parameter": {
"source": "payload",
"name": "data.state.playbackState"
}
}
},
{
"match": {
"type": "value",
"value": "STOPPED",
"parameter": {
"source": "payload",
"name": "data.state.playbackState"
}
}
}
]
}
]
}
There are two ways you can do this, via arguments or environment variables. You can read more about that here
Let's do it via environment variables: we want to pass the playbackState
and roomName
field values to the script as PLAYBACK_STATE
and ROOM_NAME
respectively. In order to do that, we define pass-environment-to-command
property on the hook like so:
"pass-environment-to-command": [
{
"source": "payload",
"envname": "ROOM_NAME",
"name": "data.roomName"
},
{
"source": "payload",
"envname": "PLAYBACK_STATE",
"name": "data.state.playbackState"
}
]
Following all this, and starting with your example, the final hook definition looks like this:
[
{
"id": "sonos",
"execute-command": "/etc/webhook/kitchen_music_on.sh",
"response-message": "Ok ...",
"pass-environment-to-command": [
{
"source": "payload",
"envname": "ROOM_NAME",
"name": "data.roomName"
},
{
"source": "payload",
"envname": "PLAYBACK_STATE",
"name": "data.state.playbackState"
}
],
"trigger-rule": {
"and": [
{
"match": {
"type": "value",
"value": "Kitchen",
"parameter": {
"source": "payload",
"name": "data.roomName"
}
}
},
{
"or": [
{
"match": {
"type": "value",
"value": "PLAYING",
"parameter": {
"source": "payload",
"name": "data.state.playbackState"
}
}
},
{
"match": {
"type": "value",
"value": "STOPPED",
"parameter": {
"source": "payload",
"name": "data.state.playbackState"
}
}
}
]
}
]
}
}
]
This hook will execute your script only when the room name is equal to Kitchen
and playback state is either PLAYING
or STOPPED
. When your script gets executed, you will have ROOM_NAME
and PLAYBACK_STATE
environment variables available. Based on values of the PLAYBACK_STATE
environment variable you can execute curl
command with different parameters.
Hope this clears up some things :-)
@adnanh , thank you much for the detailed reply! This is great info and clarifies many of the questions that I came to. I did make much progress after opening the ticket and I closed it after I got it working, mostly. Your examples fill in the gaps and I will apply them shortly.
I did have a question about how I ended up handing multiple scenarios for the Playing vs Stopped. Rather than using pass-environment-to-command, I ended up creating 2 ids with the same name "sonos" and that seemed to work. However, I am wondering if that would cause an issue of some kind. I probably should rewrite to pass-environment-to-command like your last example. Here is the code that I had made up to the point that I closed the ticket. Again, thanks much for the detailed explanations.
[{
"id": "sonos",
"execute-command": "/etc/webhook/kitchen_music_on.sh",
"response-message": "Ok ...",
"trigger-rule": {
"and": [{
"match": {
"type": "value",
"value": "Kitchen",
"parameter": {
"source": "payload",
"name": "data.roomName"
}
}
},
{
"match": {
"type": "value",
"value": "PLAYING",
"parameter": {
"source": "payload",
"name": "data.state.playbackState"
}
}
}
]
}
},
{
"id": "sonos",
"execute-command": "/etc/webhook/kitchen_music_off.sh",
"response-message": "Ok ...",
"trigger-rule": {
"and": [{
"match": {
"type": "value",
"value": "Kitchen",
"parameter": {
"source": "payload",
"name": "data.roomName"
}
}
},
{
"match": {
"type": "value",
"value": "PAUSED_PLAYBACK",
"parameter": {
"source": "payload",
"name": "data.state.playbackState"
}
}
}
]
}
}
]
The multiple hooks with the same id has been deprecated and removed in latest versions of webhook. You are most likely running an older version of webhook, since it worked for you. I strongly suggest for you to upgrade to the latest version :-) (and rewrite the hook definitions to use one hook)
Will do. Thank you!
Digging further into converting this to send pass the environment to the CURL command, can you explain further how I pass the variables? Right now I have 2 different scripts on my server that get run and execute the CURL commands; kitchen_music_on.sh and kitchen_music_off.sh. I don't guess there is a way to run the CURL directly from Webhook server is there? Like I mentioned before, my scripts either issue a CURL with the ON name or another with the OFF. The script looks like this.
#!/bin/sh
curl "https://maker.ifttt.com/trigger/Music_On/with/key/secret"
and
#!/bin/sh
curl "https://maker.ifttt.com/trigger/Music_Off/with/key/secret"
Below is the hooks.json that I have working at the moment using the forked image of palmer/webhook:docker-1.10-git
and like you say, it is not the latest.
[{
"id": "sonos",
"execute-command": "/etc/webhook/kitchen_music_on.sh",
"response-message": "Kitchen Music On ...",
"trigger-rule": {
"and": [{
"match": {
"type": "value",
"value": "Kitchen",
"parameter": {
"source": "payload",
"name": "data.roomName"
}
}
},
{
"match": {
"type": "value",
"value": "PLAYING",
"parameter": {
"source": "payload",
"name": "data.state.playbackState"
}
}
}
]
}
},
{
"id": "sonos",
"execute-command": "/etc/webhook/kitchen_music_off.sh",
"response-message": "Kitchen Music Paused or Stopped ...",
"trigger-rule": {
"and": [{
"match": {
"type": "value",
"value": "Kitchen",
"parameter": {
"source": "payload",
"name": "data.roomName"
}
}
},
{
"or": [{
"match": {
"type": "value",
"value": "PAUSED_PLAYBACK",
"parameter": {
"source": "payload",
"name": "data.state.playbackState"
}
}
},
{
"match": {
"type": "value",
"value": "STOPPED",
"parameter": {
"source": "payload",
"name": "data.state.playbackState"
}
}
}
]
}
]
}
}
]
hi @psmith3 you need to to use the "pass-environment-to-command" to use as environment variables or ""pass-arguments-to-command". I'm sure you will get a more detialed response but below might help..
Below is an example of using as environment variables. you should see in the hook verbose logs that is grabs them. Then in your script use the normal environment variable e.g. $INTERNAL_IP to call it
"id": "email",
"execute-command": "/webhook/src/email.sh",
"command-working-directory": "/webhook/src",
"pass-environment-to-command": [
{
"envname": "INTERNAL_IP",
"source": "payload",
"name": "data.INTERNAL_IP"
Also in the Wiki you can see some examples but maybe not the one above
Just to expand on what I sent. Below is what my JSON payload looks like (what I'm sending over in the webhook call) hence how it looks within the webhook JSON (above) to extract the data. `
"data":{ "EXTERNAL_IP":"", "INTERNAL_IP":"172.18.4.38", `
Thanks. Making more sense. I am hoping someone can show me an example of passing the payload into a CURL script and inserting into the variables into the URL that is sent by the script.
So it's really just a scripting issue versus the webhook right? I think you can just use ${}
cURL "https://someurl/place/${ENV}/something"
However I'm a bit of a newbie but I'm sure after a few goes and using a print comment you can test how this translates
Using the environment variables you can use Case statements to control the flow of your script, like so:
#!/bin/bash
case "$PLAYBACK_STATE" in
PLAYING)
curl playingurl
;;
STOPPED)
curl stoppedurl
;;
*)
echo "Invalid playback state $PLAYBACK_STATE"
exit 1
esac
Thanks much for the reply and explanation. I will give this a try.
P.S. You might want to check almir/docker-webhook for the up-to-date dockerized webhook :-)
Happy hacking!
I am trying to figure out how to parse the body of a webhook message sent from node-sonos-http-api and have a match to an ID in my hooks.json config that matches when my Kitchen Sonos player ("roomName":"Kitchen",) is PLAYING and another when it is STOPPED ("playbackState":"PLAYING"). Below is the raw body of the webhook message that I am needing to create two rules for under one ID in my hooks.json file because the node-sonos-http-api only can send to a single webhook server url. Ultimately, I need to have the execute command be variable and send a different url to IFTTT like https://maker.ifttt.com/trigger/Kitchen_Music_Off and another like https://maker.ifttt.com/trigger/Kitchen_Music_On. I am not sure how to pass variables from the hooks.json file to the scripts that executes a CURL to IFTTT.
RAW BODY
{"type":"transport-state","data":{"uuid":"RINCON_000E583A2E2401400","coordinator":"RINCON_000E583A2E2401400","roomName":"Kitchen","state":{"volume":22,"mute":false,"equalizer":{"bass":9,"treble":10,"loudness":true},"currentTrack":{"artist":"Taylor Swift","title":"...Ready For It?","album":"Reputation","albumArtUri":"/getaa?s=1&u=x-sonos-http%3aondemand_track%253a%253atra.290429750%257cv1%257cALBUM%257calb.290429749.mp4%3fsid%3d202%26flags%3d8224%26sn%3d2","duration":208,"uri":"x-sonos-http:ondemand_track%3a%3atra.290429750%7cv1%7cALBUM%7calb.290429749.mp4?sid=202&flags=8224&sn=2","type":"track","stationName":"","absoluteAlbumArtUri":"http://172.30.17.220:1400/getaa?s=1&u=x-sonos-http%3aondemand_track%253a%253atra.290429750%257cv1%257cALBUM%257calb.290429749.mp4%3fsid%3d202%26flags%3d8224%26sn%3d2"},"nextTrack":{"artist":"Taylor Swift","title":"End Game","album":"Reputation","albumArtUri":"/getaa?s=1&u=x-sonos-http%3aondemand_track%253a%253atra.290429751%257cv1%257cALBUM%257calb.290429749.mp4%3fsid%3d202%26flags%3d8224%26sn%3d2","duration":245,"uri":"x-sonos-http:ondemand_track%3a%3atra.290429751%7cv1%7cALBUM%7calb.290429749.mp4?sid=202&flags=8224&sn=2","absoluteAlbumArtUri":"http://172.30.17.220:1400/getaa?s=1&u=x-sonos-http%3aondemand_track%253a%253atra.290429751%257cv1%257cALBUM%257calb.290429749.mp4%3fsid%3d202%26flags%3d8224%26sn%3d2"},"trackNo":1,"elapsedTime":26,"elapsedTimeFormatted":"00:00:26","playbackState":"PLAYING","playMode":{"repeat":"none","shuffle":false,"crossfade":true}},"groupState":{"volume":22,"mute":false},"avTransportUri":"x-rincon-queue:RINCON_000E583A2E2401400#0","avTransportUriMetadata":""}} {"type":"transport-state","data":{"uuid":"RINCON_000E583A2E2401400","coordinator":"RINCON_000E583A2E2401400","roomName":"Kitchen","state":{"volume":22,"mute":false,"equalizer":{"bass":9,"treble":10,"loudness":true},"currentTrack":{"artist":"Taylor Swift","title":"...Ready For It?","album":"Reputation","albumArtUri":"/getaa?s=1&u=x-sonos-http%3aondemand_track%253a%253atra.290429750%257cv1%257cALBUM%257calb.290429749.mp4%3fsid%3d202%26flags%3d8224%26sn%3d2","duration":208,"uri":"x-sonos-http:ondemand_track%3a%3atra.290429750%7cv1%7cALBUM%7calb.290429749.mp4?sid=202&flags=8224&sn=2","type":"track","stationName":"","absoluteAlbumArtUri":"http://172.30.17.220:1400/getaa?s=1&u=x-sonos-http%3aondemand_track%253a%253atra.290429750%257cv1%257cALBUM%257calb.290429749.mp4%3fsid%3d202%26flags%3d8224%26sn%3d2"},"nextTrack":{"artist":"Taylor Swift","title":"End Game","album":"Reputation","albumArtUri":"/getaa?s=1&u=x-sonos-http%3aondemand_track%253a%253atra.290429751%257cv1%257cALBUM%257calb.290429749.mp4%3fsid%3d202%26flags%3d8224%26sn%3d2","duration":245,"uri":"x-sonos-http:ondemand_track%3a%3atra.290429751%7cv1%7cALBUM%7calb.290429749.mp4?sid=202&flags=8224&sn=2","absoluteAlbumArtUri":"http://172.30.17.220:1400/getaa?s=1&u=x-sonos-http%3aondemand_track%253a%253atra.290429751%257cv1%257cALBUM%257calb.290429749.mp4%3fsid%3d202%26flags%3d8224%26sn%3d2"},"trackNo":1,"elapsedTime":26,"elapsedTimeFormatted":"00:00:26","playbackState":"PLAYING","playMode":{"repeat":"none","shuffle":false,"crossfade":true}},"groupState":{"volume":22,"mute":false},"avTransportUri":"x-rincon-queue:RINCON_000E583A2E2401400#0","avTransportUriMetadata":""}}
Just to get started, I have been tinkering with the following hooks.json file and cannot figure out how to get a simple match on the playingback state. Am I on the right track?
Any help would be much appreciated.