Polycom VVX Call State via PHP and MQTT

This is my first complete homebrew solution to integrate my home office phone into home assistant. Basically, I like media playing while I am working, but would like to pause music if I am taking a phone call. It requires a PHP web server, MQTT broker, VVX phone, and optionally media players to control. I never programmed in PHP before, so excuse perhaps some sloppy code. I really can’t wrap my head around Python as a C# developer. Someday I will figure out how to make this a component.

Polycom only offers call state data in its XML format, this parses the XML and produces appropriate information based on what is received. Only tested on Polycom VVX 500.

polycom.php
<?php
use Mosquitto\Client;

$random = rand();
define('BROKER', 'localhost');
define('PORT', 1883);
define('CLIENT_ID', (string)"vvx_proxy_{$random}");
define('USERNAME', "username");
define('PASSWORD', "password");

$client = new Mosquitto\Client(CLIENT_ID);
$client->setCredentials(USERNAME,PASSWORD);
$responsecode = 500;

$xml = simplexml_load_string(file_get_contents("php://input"), "SimpleXMLElement", LIBXML_NOCDATA);

$mid = 0;
$client->onConnect(function() use ($client, $mid, $xml) {
    //$mid = $client->publish('phone/status', print_r($xml, true), 0, false);
	$mac = $xml->CallStateChangeEvent->MACAddress;
	$statetopic = (string)"phone/{$mac}/state";
	$attributetopic = (string)"phone/{$mac}/attributes";
	
	$state = (string)$xml->CallStateChangeEvent->attributes()['CallState'];
	$attributes = array();
	$lineinfo = $xml->CallStateChangeEvent->CallLineInfo;
	foreach ($lineinfo as $line) {
		$linenum = $line->LineKeyNum;
		$linestate = $line->LineState;
		$attributes["line_{$linenum}_state"] = (string)$linestate;
		
		$callstate = $linestate;
		$calltype = "None";
		$calledpartyname = "";
		$callingpartyname = "";
		
		if (property_exists($line, 'CallInfo')) {
			$callinfo = $line->CallInfo;
			if (property_exists($callinfo, 'CallState')) {
				$callstate = $callinfo->CallState;
			}
			if (property_exists($callinfo, 'CallType')) {
				$calltype = $callinfo->CallType;
			}
			if (property_exists($callinfo, 'CalledPartyName')) {
				$calledpartyname = $line->CallInfo->CalledPartyName;
			}
			if (property_exists($callinfo, 'CallingPartyName')) {
				$callingpartyname = $line->CallInfo->CallingPartyName;
			}
		}
		$attributes["line_{$linenum}_call_state"] = (string)$callstate;
		$attributes["line_{$linenum}_call_type"] = (string)$calltype;
		$attributes["line_{$linenum}_called_party_name"] = (string)$calledpartyname;
		$attributes["line_{$linenum}_calling_party_name"] = (string)$callingpartyname;
	}
	
	$mid = $client->publish($statetopic,$state,0,false);
	$mid = $client->publish($attributetopic,json_encode($attributes),0,false);
});

$client->onPublish(function($publishedId) use ($client, $mid, $responsecode) {
    $client->disconnect();
    $responsecode = 200;
});

$client->connect(BROKER, PORT, 60);
$client->loopForever();

http_response_code($responsecode);
?>

mqtt sensor YAML
{mac} in the format of xxxxxxxxxxxxxx

  • platform: mqtt
    state_topic: “phone/{mac}/state”
    name: Phone
    icon: mdi:deskphone
    json_attributes_topic: “phone/{mac}/attributes”
    unique_id: phone_{mac}

office automation to announce caller

  • id: phone_offering
    alias: Phone Offering Phone Call
    initial_state: ‘on’
    trigger:
    • platform: state
      entity_id: sensor.phone
      to: ‘Offering’
      action:
    • delay: 00:00:01
    • service: tts.google_say
      entity_id: media_player.home_speaker
      data_template:
      message: Incoming telephone call from {{ states.sensor.office_phone.attributes.line_1_calling_party_name }}.

office automation to pause playback

  • id: phone_busy_disable_speaker
    alias: Phone Busy Disable Speaker
    initial_state: ‘on’
    trigger:
    • platform: state
      entity_id: sensor.phone
      from: ‘Free’
      condition:
      condition: state
      entity_id: media_player.office_speaker
      state: ‘playing’
      action:
    • service: automation.turn_on
      entity_id: automation.phone_busy_enable_speaker
    • service: media_player.media_pause
      entity_id: media_player.office_speaker

office automation to resume playback

  • id: phone_busy_enable_speaker
    alias: Phone Busy Enable Speaker
    initial_state: ‘off’
    trigger:
    • platform: state
      entity_id: sensor.phone
      to: ‘Free’
      action:
    • service: media_player.media_play
      entity_id: media_player.office_speaker
    • service: automation.turn_off
      entity_id: automation.phone_busy_enable_speaker
2 Likes

This looks awesome, totally GENIUS. Exactly what I was looking for and more! I’m about to try setting it up right now.

How well has it been working for you? Any issues or has it just been smooth sailing?

Actually it is working pretty great. Since working from home, the benefits are clearer - whenever I prepare to make a phone call (or in the process of receiving one) everything mutes and I can carry on the telephone call free of background noise (or having to annoying say “OK Google” with someone on the other line.

If there is one automation I have been on the fence about since implementing it this way, it is announcing the caller. Not exactly a fan of it now that I get more phone calls on a “landline” than I did in the past.

1 Like

Yeah, I can see how that might get old, perhaps there may be a way to have it only announce the callerID if the contact is not in your contacts list, or if the caller has called once within a certain period of time like within 24 hours or so. Also changing the speed and pitch of the Google TTS could help too. I’m gonna try to get this running today and I’ll let you know my results. I’m very excited, and very aware of how nerdy that sounds, being excited about caller ID, its like being in 1997 again lol.

Where exactly do you put the polycom.php file? Is this what gets hosted on the php server requirement? Also, where do you find the mqtt.yaml? Or is this a file that simply needs to be created under the /config folder of the homeassistant server isntance? I’m attempting to run this off of either my VVX400 or VVX600 if that helps.

The php file is hosted on an apache server as a virtual host; any PHP compatible HTTP server should work. Basically, I use rewirtes and reverse proxy with apache to connect so I have ha.example.org and a polycom.example.org virtual hosts.

The MQTT yaml is just a sensor, so it should be part of the sensor config of your main configuration.

For my Polycom VVX 500, I configured this under Settings > Applications. The notifications URL is my http://polycom.example.org/polycom.php; and I just checked Call State Change (the rest of the options were unchecked).

Some of you might be interested in this: Dashboard addon for Polycom VVX microbrowser

I’ve thought about adding this call state component to my flask based server but I don’t really have a need for it at the moment.

I just picked up a poly trio 8500 and found this thread. I spent too many hours trying to get this working and in the end failed. What worked very well for me instead was to use the REST API. It saved me from worrying about the whole php side of this solution. The API needed to be turned in in the polycom web admin interface - and saved!

  - platform: rest
     resource: https://192.168.1.31/api/v1/webCallControl/callStatus
     name: "Poly"
     username: Polycom
     password: xxx
     authentication: basic
     verify_ssl: false

Note that I did not setup a Polycom account, that seems to be the default API account. It uses the Admin account password. It can’t be 456 so if you used the default you must change it.
I was getting cert errors which is why i added the verfy_ssl false line.

The automation logic needs to be updated I think to reflect this use case, and ultimately for me I am just using it as a glorified bluetooth speaker so i don’t be going to far into templating - i just need to know when its in use or not - nothing fancy. Once I finalize my setup ill post my automation - to stop my owntone when phone is in use. Unfortunately in my use case with bluetooth i cant see how to distuingish between an alert of a new email or notification, vs a teams call. I will have a lot of false muting / resumes but better than me manually pausing.

1 Like

This is exactly what I just did too. Rest API is working great for me for phone status and I can use that to trigger automations like pause music when phone is active. I have it set to check every 2 seconds to have a quick response.