Disect a UPnP error, and raise an appropriate exception.

        Args:
            xml_error (str):  a unicode string containing the body of the
                UPnP/SOAP Fault response. Raises an exception containing the
                error code.

def handle_upnp_error(self, xml_error):
        """Disect a UPnP error, and raise an appropriate exception.

        Args:
            xml_error (str):  a unicode string containing the body of the
                UPnP/SOAP Fault response. Raises an exception containing the
                error code.
        """

        # An error code looks something like this:

        # HTTP/1.1 500 Internal Server Error
        # CONTENT-LENGTH: bytes in body
        # CONTENT-TYPE: text/xml; charset="utf-8"
        # DATE: when response was generated
        # EXT:
        # SERVER: OS/version UPnP/1.0 product/version

        # <?xml version="1.0"?>
        # <s:Envelope
        #   xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
        #   s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
        #   <s:Body>
        #       <s:Fault>
        #           <faultcode>s:Client</faultcode>
        #           <faultstring>UPnPError</faultstring>
        #           <detail>
        #               <UPnPError xmlns="urn:schemas-upnp-org:control-1-0">
        #                   <errorCode>error code</errorCode>
        #                   <errorDescription>error string</errorDescription>
        #               </UPnPError>
        #           </detail>
        #       </s:Fault>
        #   </s:Body>
        # </s:Envelope>
        #
        # All that matters for our purposes is the errorCode.
        # errorDescription is not required, and Sonos does not seem to use it.

        # NB need to encode unicode strings before passing to ElementTree
        xml_error = xml_error.encode('utf-8')
        error = XML.fromstring(xml_error)
        log.debug("Error %s", xml_error)
        error_code = error.findtext(
            './/{urn:schemas-upnp-org:control-1-0}errorCode')
        if error_code is not None:
            description = self.UPNP_ERRORS.get(int(error_code), '')
            raise SoCoUPnPException(
                message='UPnP Error {} received: {} from {}'.format(
                    error_code, description, self.soco.ip_address),
                error_code=error_code,
                error_description=description,
                error_xml=xml_error
            )
        else:
            # Unknown error, so just return the entire response
            log.error("Unknown error received from %s", self.soco.ip_address)
            raise UnknownSoCoException(xml_error)