Need help phasing HTTP JSON response from audio matrix

Hey all,

I’m trying to integrate with a software audio matrix and i’m hitting a bit of a wall. I’ve got it working with the exception of volume, EQ, and mute. 3 pretty important controls for an audio matrix…

The problem with mute is the Json response is true or false but i’d like to be able to just switch it on or off. So I came up with a rule for this that works very well, but I can’t stop thinking it could be easier done (maybe with a transform). Is there an easier way to convert true to on and false to off?

Volume and EQ i’m having the same issue. The response is in hundredths and i’d like it in ones without the decimal. The audio matrix range for vol, bass, mid, and high is 0.01 (0.00 is the same as mute) to 1. 0.50 equals 50%, 0.99 equals 99% and 1 equals 100%. This means all 4 dimmers are always set to 0 and even if I could send a command it would set the zone to 100% no matter what I set the dimmer to. How can I pull in these values, rescale them, and convert from decimal? As if that wasn’t hard enough (for me anyways), to send the command is worse. The rest command is formatted as:

http://192.168.1.190:5050/api/v1/json/SetZoneVolume?zoneName={ZONENAME}&volume={VOLUME}

It’s expecting a specific value for {VOLUME} and it must be in hundredths (0.50 for 50%). I’m not sure how to do this at the item binding level. My guess is i’d have to do it with a rule or a transform and that’s why I created the volume_proxy item, but I’m thinking maybe there’s a better way and in either case i’m not sure how to do it. Any and all help would be greatly appreciated.

The JSON response looks like:

{“AllowedPlayersID”:[],“AudioDevice”:{“DeviceInfo”:{“a”:{“a”:{“value”:9307560},“b”:{“value”:8940376},“c”:1},“driver”:"{0.0.0.00000000}.{d83ba6a8-1a30-4e1f-8531-d3e4c9979f7d}",“flags”:1,“id”:“usb#vid_0d8c&pid_0008&mi_00#6&804d734&0&0000#{6994ad04-93ef-11d0-a3cc-00a0c9223196}\global”,“name”:“Speakers (2- C-Media USB Audio Device )”},“DeviceInfoName”:“Speakers (2- C-Media USB Audio Device )”,“Id”:3,“LatencyMS”:40},“Channels”:16777216,“ID”:“ebbeebae-0b27-47d6-8938-3dbab712b43a”,“Muted”:false,“Name”:“FamilyRoom”,“ParamEQ”:[{“fBandwidth”:18,“fCenter”:100,“fGain”:15},{“fBandwidth”:18,“fCenter”:1000,“fGain”:15},{“fBandwidth”:18,“fCenter”:8000,“fGain”:15}],“Stereo”:false,“Volume”:0.4}

So I created the following in OH:

Items (ignore the extra “>”):

> String Media_AudioZone_ZoneDeck_ID	{http="<[http://192.168.1.190:5050/api/v1/json/GetZoneByName?name=Deck:10000:REGEX((.*))]"}
> Switch Media_AudioZone_ZoneDeck_Enabled "Deck Zone Power"	(gZoneAudioZonesDeck)
> String Media_AudioZone_ZoneDeck_Mute "Deck Zone Mute"	(gZoneAudioZonesDeck)	{http=">[ON:GET:http://192.168.1.190:5050/api/v1/json/SetZoneMute?zoneName=Deck&mute=true] >[OFF:GET:http://192.168.1.190:5050/api/v1/json/SetZoneMute?zoneName=Deck&mute=false]"}
> Number Media_AudioZone_ZoneDeck_Volume "Deck Zone Volume"	(gZoneAudioZonesDeck)  {http="<[http://192.168.90.190:5050/api/v1/json/GetZoneByName?name=Deck:10000:JS(zoneAudioVol.js)] >[*:GET:http://192.168.90.190:5050/api/v1/json/SetZoneVolume?zoneName=Deck&volume=%2$.1f]"}
> Number Media_AudioZone_ZoneDeck_Volume_Proxy "Deck Zone Proxy Volume"
> Dimmer Media_AudioZone_ZoneDeck_Bass "Deck Zone EQ Bass"	(gZoneAudioZonesDeck)
> Dimmer Media_AudioZone_ZoneDeck_Mid "Deck Zone EQ Mid"	(gZoneAudioZonesDeck)
> Dimmer Media_AudioZone_ZoneDeck_High "Deck Zone EQ High"	(gZoneAudioZonesDeck)

Transform/zoneAudioVol.js

(function(i) {
var json = JSON.parse(i);
return json[‘Volume’];
})(input)

Rules:

 rule "Deck Zone Status"
  when 
	system started or
    Item Media_AudioZone_ZoneDeck_ID received update
  then
    Thread::sleep(1000)
      var String jsonDeck = (Media_AudioZone_ZoneDeck_ID.state as StringType).toString
	  var String NameDeck = transform("JSONPATH", "$.Name", jsonDeck)
	if (NameDeck == "Deck"){	  
		var String muteDeck  = transform("JSONPATH", "$.Muted", jsonDeck)
		if(muteDeck == "ture"){
			postUpdate(Media_AudioZone_ZoneDeck_Mute, ON)}
		else
		if(muteDeck == "false"){
			postUpdate(Media_AudioZone_ZoneDeck_Mute, OFF)}
	}
  end
1 Like

In the end this boils down to “I don’t know what I don’t know”. I got it working pretty close to what I in visioned. May not be pretty but it works pretty good for me (at the moment anyways). In the event that someone find this one day here’s what I ended up doing. If someone sees room for improvement, please let me know.

For mute, I couldn’t find a better way. I’m now confident I can do it with a transform file but I just can’t get the syntax right. I forgot I’m formatting values from one of my thermostats with a transform file in a similar manner. For the life of me I was not able to adapt the file to work in this scenario. O well. The current setup works.

For Mute:
Item file:

Switch Media_AudioZone_ZoneDeck_Mute “Deck Zone Mute” (gZoneAudioZonesDeck) {http=">[ON:GET:http://192.168.1.190:5050/api/v1/json/SetZoneMute?zoneName=Deck&mute=true] >[OFF:GET:http://192.168.1.190:5050/api/v1/json/SetZoneMute?zoneName=Deck&mute=false]"}

Rule:

Thread::sleep(200)
  var String jsonDeck = (Media_AudioZone_ZoneDeck_Raw.state as StringType).toString
	  var String NameDeck = transform("JSONPATH", "$.Name", jsonDeck)
	if (NameDeck == "Deck"){	  
		var String IDDeck  = transform("JSONPATH", "$.ID", jsonDeck)
		var String muteDeck  = transform("JSONPATH", "$.Muted", jsonDeck)
		if(muteDeck == "ture"){
			postUpdate(Media_AudioZone_ZoneDeck_Mute, ON)}
		else
		if(muteDeck == "false"){
			postUpdate(Media_AudioZone_ZoneDeck_Mute, OFF)}
		postUpdate(Media_AudioZone_ZoneDeck_ID,  IDDeck)
	}

As you can see i’m making the REST calls directly with the item via the HTTp binding. I’m updating the state of the switch item with a rule that’s parsing the entire JSON response and pulling out the mute status.

Volume, and EQ:
To update the status of the 4 dimmer items representing VOl, Bass, Mid, and High, i’m using a transform file to capture the entire JSON output, pull out the value and multiply each by 100 to get the correct final value. This allows the dimmers to display the correct level. This can be done with the same rule block above and I have a few zones still setup that way for testing. I may switch to that method as it only require the JSON output to be parsed once.

To send the command to Volume and EQ via a rule I’m using sendHttpGetRequeste. sendHttpGetRequest is what I didn’t know. I knew something like this existed but I didn’t know how to ask and I definitely didn’t know the syntax. Using a rule, when the dimmer changes I take the new value and divide it by 100, save it to a var, then I use that var to create a new var, and I use sendHttpGetRequest to send the new var.

Rule:

rule "Deck Zone Volume"
when
Item Media_AudioZone_ZoneDeck_Volume received command
then
var volCurrentDeckWork = receivedCommand
logInfo(“ZoneAudio”, “Deck Zone Volume Raw Val:” + volCurrentDeckWork)
var volCurrentDeck = ((volCurrentDeckWork as DecimalType)/100)
logInfo(“ZoneAudio”, “Deck Zone Volume Current:” + volCurrentDeck)
var String volDeckHTTPString = “http://192.168.1.190:5050/api/v1/json/SetZoneVolume?zoneName=Deck&volume=” + volCurrentDeck
logInfo(“ZoneAudio”, “Deck Zone Volume Req:” + volDeckHTTPString)
sendHttpGetRequest(volDeckHTTPString)
end

Transform:

(function(i) {
var json = JSON.parse(i);
return json[‘Volume’]*100;
})(input)

Item:

Dimmer Media_AudioZone_ZoneDeck_Volume “Deck Zone Volume” (gZoneAudioZonesDeck) {http="<[http://192.168.90.190:5050/api/v1/json/GetZoneByName?name=Deck:500:JS(zoneAudioVol.js)]"}

If you’re paying attention you’ll notice that i’m polling the snot out of the audio matrix at 500 ms. There are about 20 items refreshing at that rate. If you’re adapting this for a hardware solution, over wifi, or a low powered device, this may cause an issue on the receiving end. This audio matrix is software based and is running on a “full powered” windows PC. I say full powered but it’s an old single core celeron I keep laying around for proof of concept builds, doesn’t even have hyper threading. I’m currently using it as an appliance (i’ll be replacing it with new permanent hardware soon) I installed OH on it and configured it to talk via MQTT. My primary OH instance will have to subscribe to the correct topics to control the audio matrix, just like any other appliance you’d intergrate. For me this approach lines up with my system design. This means that the rules above are running on the same machine as the matrix and the http polling is actually happening locally and not across the network.

Basically, if you’re still reading this I got it working to my liking. I’m still open to suggestions to make it better but it works. In case someone in a similar situation finds this hopefully it will help. Nothing throws me over the edge faster than racking my brain on an issue, finding threads where that exact same question was asked, but no responses at all. Not even an update from the OP. I’m not knocking the OH community with that, this is a global internet wide issue, IMO. Well, hopefully this helps someone one day.