def test_recreate_authentication_v4_psk(self): device = SonyDevice("test", "test", "foobarPSK") device.pin = 1234 self.add_register_to_device(device, 4) device._recreate_authentication() self.assertTrue(device.psk) self.assertEqual(device.headers["X-Auth-PSK"], device.psk)
def sony_configuration_callback(data): """Handle the entry of user PIN.""" from sonyapilib.device import SonyDevice, AuthenticationResult pin = data.get('pin') sony_device = SonyDevice(host, name) auth_mode = sony_device.get_action("register").mode authenticated = False # make sure we only send the authentication to the device # if we have a valid pin if pin == '0000' or pin is None or pin == '': register_result = sony_device.register() if register_result == AuthenticationResult.SUCCESS: authenticated = True elif register_result == AuthenticationResult.PIN_NEEDED: # return so next call has the correct pin return else: _LOGGER.error("An unknown error occured during registration") # devices below version 3 do not require a pin. if auth_mode > 2: authenticated = sony_device.send_authentication(pin) if authenticated: setup_sonymediaplayer(config, pin, hass, add_devices) else: request_configuration(config, hass, add_devices)
def create_device(): """Create a new device instance""" sonyapilib.device.TIMEOUT = 0.1 device = SonyDevice("test", "test") device.api_version = 3 device.cookies = jsonpickle.decode(read_file("data/cookies.json")) return device
def sony_configuration_callback(data): """Handle the entry of user PIN.""" from sonyapilib.device import AuthenticationResult pin = data.get('pin') sony_device = SonyDevice(host, name, psk=psk, app_port=app_port, dmr_port=dmr_port, ircc_port=ircc_port) authenticated = False # make sure we only send the authentication to the device # if we have a valid pin if pin == '0000' or pin is None or pin == '': register_result = sony_device.register() if register_result == AuthenticationResult.SUCCESS: authenticated = True elif register_result == AuthenticationResult.PIN_NEEDED: # return so next call has the correct pin return else: _LOGGER.error("An unknown error occured during registration") authenticated = sony_device.send_authentication(pin) if authenticated: setup_sonymediaplayer(config, sony_device, hass, add_devices) else: request_configuration(config, hass, add_devices)
def registration_start(self): ''' register device / device must be on for registration -> request registration ''' self.logging.info("SONY Start Registration") self.device = SonyDevice(self.device_ip, self.device_name) self.device.register() self.waiting_for_registration = True return "SONY Device is waiting for PIN"
def test_save_load_from_json(self): device = self.create_device() jdata = device.save_to_json() restored_device = SonyDevice.load_from_json(jdata) jdata_restored = restored_device.save_to_json() self.assertEqual(jdata, jdata_restored) self.assertEqual(restored_device.client_id, device.client_id)
def load_device(): """Restore the device from disk.""" import os sony_device = None if os.path.exists(CONFIG_FILE): with open(CONFIG_FILE, 'r') as content_file: json_data = content_file.read() sony_device = SonyDevice.load_from_json(json_data) return sony_device
def __init__(self, host, name, pin, mac=None): """ Initialize the Sony mediaplayer device. Mac address is optional but neccessary for wake on LAN """ from sonyapilib.device import SonyDevice self._pin = pin self.sonydevice = SonyDevice(host, name) self._name = name self._state = STATE_OFF self._muted = False self._id = None self._playing = False self.sonydevice.pin = pin self.sonydevice.mac = mac try: self.sonydevice.update_service_urls() self.update() except Exception: # pylint: disable=broad-except self._state = STATE_OFF
def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Sony Media Player platform.""" host = config.get(CONF_HOST) if host is None: return pin = None sony_config = load_json(hass.config.path(SONY_CONFIG_FILE)) while sony_config: # Set up a configured TV host_ip, host_config = sony_config.popitem() if host_ip == host: device = SonyDevice.load_from_json(host_config) hass_device = SonyMediaPlayerEntity(device) add_devices([hass_device]) return setup_sonymediaplayer(config, pin, hass, add_devices)
def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Sony Media Player platform.""" host = config.get(CONF_HOST) if host is None: return pin = None sony_config = load_json(hass.config.path(SONY_CONFIG_FILE)) from sonyapilib.device import SonyDevice while sony_config: # Set up a configured TV host_ip, host_config = sony_config.popitem() if host_ip == host: device = SonyDevice.load_from_json(host_config['device']) hass_device = SonyMediaPlayerDevice(host, device.nickname, device.pin, device.mac) hass_device.sonydevice = device add_devices([hass_device]) return setup_sonymediaplayer(config, pin, hass, add_devices)
def load_device(self): ''' Restore the device from disk. Config file will be created during the registration process. ''' import os sony_device = None self.logging.info("SONY load: " + self.device_ip + ", " + self.device_name + ", " + self.device_config) try: if os.path.exists(self.device_config): with open(self.device_config, 'r') as content_file: json_data = content_file.read() sony_device = SonyDevice.load_from_json(json_data) else: self.logging.error("SONY load device: file not found (" + self.device_config + ")") return sony_device except Exception as e: self.logging.error("SONY load device: " + str(e))
def test_irrc_is_dmr(self): dev = SonyDevice(host="none", nickname="none", ircc_port=42, dmr_port=42) self.assertEqual(dev.dmr_url, dev.ircc_url)
"""Restore the device from disk.""" import os sony_device = None if os.path.exists(CONFIG_FILE): with open(CONFIG_FILE, 'r') as content_file: json_data = content_file.read() sony_device = SonyDevice.load_from_json(json_data) return sony_device if __name__ == "__main__": device = load_device() if not device: # device must be on for registration host = "192.168.178.23" device = SonyDevice(host, "Test123") device.register() pin = input("Enter the PIN displayed at your device: ") if device.send_authentication(pin): save_device() else: print("Registration failed") exit(1) # wake device is_on = device.get_power_status() if not is_on: device.power(True) status = device.get_playing_status()
"""Example found in the readme.""" from sonyapilib.device import SonyDevice if __name__ == "__main__": # device must be on for registration host = "10.0.0.102" device = SonyDevice(host, "SonyApiLib Python Test") device.register() pin = input("Enter the PIN displayed at your device: ") if not device.send_authentication(pin): print("Failed to register device") exit(1) apps = device.get_apps() device.start_app(apps[0]) device.play()
class sonyDevice(): ''' Create Sony device ''' def __init__(self, ip, name, config): ''' initialize device ''' self.logging = logging.getLogger("api.SONYlib") self.device_ip = ip self.device_name = name self.device_config = config self.device = self.load_device() self.cache = {} self.cache_time = 0 self.available_commands = [] self.waiting_for_registration = False # SOAPcalls // tested with SONY BDP S4500 self.SOAPcalls = { "GetTransportInfo": [ "CurrentTransportState", "CurrentTransportStatus", "CurrentSpeed" ], "GetMediaInfo": [ "NrTracks", "MediaDuration", "CurrentURI", "CurrentURIMetaData", "NextURI", "NextURIMetaData", "PlayMedium", "RecordMedium", "WriteStatus" ], "GetDeviceCapabilities": ["PlayMedia", "RecMedia", "RecQualityModes"], "GetTransportSettings": ["PlayMode", "RecQualityMode"], "GetPositionInfo": [ "Track", "TrackDuration", "TrackMetaData", "TrackURI", "RelTime", "AbsTime", "RelCount", "AbsCount" ], "GetCurrentTransportActions": ["Actions"] } # IRRCcalls // tested with SONY BDP S4500 self.IRRCcalls = { "getContentInformation": { "command": "getContentInformation", "main": "contentInformation", "items": [ "infoItem||class", "infoItem||source", "infoItem||mediaType", "infoItem||mediaFormat" ] }, "getSystemInformation": { "command": "getSystemInformation", "main": "systemInformation", "items": [ "name", "generation", "supportContentsClass::class", "supportSource::source" ] }, "getStatus": { "command": "getStatus", "main": "statusList", "items": [ "status||disc::statusItem||type", "status||disc::statusItem||mediaType", "status||disc::statusItem||mediaFormat" ] } } #----------------------------- def save_device(self): ''' Save the device to disk. ''' data = device.save_to_json() try: text_file = open(self.device_config, "w") text_file.write(data) text_file.close() except Exception as e: self.logging.error("SONY load device: " + str(e)) #----------------------------- def load_device(self): ''' Restore the device from disk. Config file will be created during the registration process. ''' import os sony_device = None self.logging.info("SONY load: " + self.device_ip + ", " + self.device_name + ", " + self.device_config) try: if os.path.exists(self.device_config): with open(self.device_config, 'r') as content_file: json_data = content_file.read() sony_device = SonyDevice.load_from_json(json_data) else: self.logging.error("SONY load device: file not found (" + self.device_config + ")") return sony_device except Exception as e: self.logging.error("SONY load device: " + str(e)) #----------------------------- def registration_start(self): ''' register device / device must be on for registration -> request registration ''' self.logging.info("SONY Start Registration") self.device = SonyDevice(self.device_ip, self.device_name) self.device.register() self.waiting_for_registration = True return "SONY Device is waiting for PIN" #----------------------------- def registration_finish(self, pin): ''' register device / device must be on for registration -> return PIN for registration and save data ''' self.logging.info("SONY Finish Registration") if self.wating_for_registration: if self.device.send_authentication(pin): self.save_device() else: return "ERROR: SONY Registration failed" else: return "ERROR: SONY Not waiting for registration" #----------------------------- def power(self, power_on): ''' switch power on / off ''' self.device.power(power_on) #----------------------------- def send(self, cmd): ''' send command ''' if cmd == "PowerOn" and self.get_status("power") == False: try: self.logging.info("SONY wake on lan: START (" + self.device.mac + "/" + self.device_ip + ")") self.device.wakeonlan(self.device_ip) time.sleep(3) except Exception as e: self.logging.error("SONY wake on lan: " + str(e)) elif cmd == "PowerOff" and self.get_status("power") == True: self.power(False) elif self.get_status("power"): if self.available_commands == []: self.available_commands = self.get_values("commands") if cmd in self.available_commands: self.device._send_command(cmd) else: return "ERROR: command not available for this device (" + cmd + ")" return "OK" else: return "ERROR: Device is off (SONY)." return "OK" #----------------------------- def get_values(self, cmd): ''' get values that are available on the device ''' if self.get_status("power"): if cmd == "apps": return self.device.get_apps() elif cmd == "actions": return self.device.actions.keys() elif cmd == "commands": self.available_commands = [] commands = self.device.commands.keys() for key in commands: self.available_commands.append(key) self.available_commands.append("PowerOn") self.available_commands.append("PowerOff") return self.available_commands else: return "ERROR: no values available (" + cmd + ")" else: return "ERROR: Device is off (SONY)." #----------------------------- def get_status_SOAP(self, param): ''' get status using a SOAP call (if type is AVTransport) Spec for UPNP-av-AVTransport: http://upnp.org/specs/av/UPnP-av-AVTransport-v1-Service.pdf ''' params = param.split("::") data = '<m:' + params[ 0] + ' xmlns:m="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></m:' + params[ 0] + '>' action = "urn:schemas-upnp-org:service:AVTransport:1#" + params[0] if self.get_status("power"): if "SOAP_" + params[ 0] not in self.cache or self.cache_time + 5 < time.time(): try: content = self.device._post_soap_request( url=self.device.av_transport_url, params=data, action=action) self.cache["SOAP_" + params[0]] = content self.cache_time = time.time() except Exception as e: return "ERROR: Request failed (" + str(e) + ")" else: content = self.cache["SOAP_" + params[0]] if params[1]: result = find_in_xml(content, [".//" + params[1]]).text else: result = str(content) return result else: return "ERROR: Device is off (SONY)." #----------------------------- def get_status_CMD(self, param): return "NOT IMPLEMENTED (TESTING)" result = "test" try: result = self.device._send_http( self.device._get_action("getContentInformation").url, method=HttpMethod.GET) self.logging.warning(result.text) result = self.device._send_http( self.device._get_action("getSystemInformation").url, method=HttpMethod.GET) self.logging.warning(result.text) result = self.device._send_http( self.device._get_action("getContentURL").url, method=HttpMethod.GET) self.logging.warning(result.text) result = self.device._send_http( self.device._get_action("getStatus").url, method=HttpMethod.GET) self.logging.warning(result.text) except Exception as e: return "ERROR: " + str(e) return str(result.text) #----------------------------- def get_status_IRRC(self, param): ''' get status using an IRRC call Spec for IRCC -> https://buildmedia.readthedocs.org/media/pdf/pyircc/latest/pyircc.pdf ''' # param = { "command" : "...", "main" : "...", "items" : "..." } # :: -> split xml tags # || -> split tag and values (1. "name=...", 2. "field=...") return "NOT IMPLEMENTED YET" #----------------------------- def get_status(self, cmd, param=""): ''' get status ... ''' self.logging.debug("SONY get_status: " + str(cmd) + "/" + str(param) + " - " + str(self.device.get_power_status())) if cmd == "power": return self.device.get_power_status() if self.device.get_power_status(): if cmd == "playing": return self.device.get_playing_status( ) # OK, PLAYING, ... NO_MEDIA_PRESENT, ... elif cmd == "SOAP": return self.get_status_SOAP(param) elif cmd == "IRRC": return self.get_status_IRRC(param) elif cmd == "CMD": return self.get_status_CMD(param) else: return "ERROR: Command not defined (" + cmd + ")" else: return "ERROR: Device is off (SONY)." #----------------------------- def start_app(self, app): ''' start app ''' if self.get_status("power"): self.device.start_app(app) return "OK" else: return "ERROR: Device is off (SONY)." #----------------------------- def test(self): ''' test system info ... checked for SONY BDP-S4500 ''' self.send("PowerOn") SOAPcalls = self.SOAPcalls IRRCcalls = self.IRRCcalls print(" ---- SOAP Calls ---- ") for key in SOAPcalls: for param in SOAPcalls[key]: value = self.get_status("SOAP", key + "::" + param) print(key + "::" + param + " = " + str(value)) print(" ---- IRRC Calls ---- ") for key in IRRCcalls: value = self.get_status("IRRC", key) print(key + " = " + str(value)) # ..... # add field to "get command" and return specific value (compared to SOAP calls) # IRCC -> https://buildmedia.readthedocs.org/media/pdf/pyircc/latest/pyircc.pdf #------------------- info = ["getContentInformation", "getSystemInformation", "getStatus"] for x in info: print(" .... " + x + " .... ") response = self.device._send_http(self.device._get_action(x).url, method=HttpMethod.GET) if response: print(response.text)
def save_device(): data = device.save_to_json() text_file = open("bluray.json", "w") text_file.write(data) text_file.close() if __name__ == "__main__": stored_config = "bluray.json" device = None import os.path if os.path.exists(stored_config): with open(stored_config, 'r') as content_file: json_data = content_file.read() device = SonyDevice.load_from_json(json_data) else: # device must be on for registration host = "10.0.0.102" device = SonyDevice(host, "SonyApiLib Python Test") device.register() pin = input("Enter the PIN displayed at your device: ") device.send_authentication(pin) save_device() # wake device is_on = device.get_power_status() if not is_on: device.power(True) apps = device.get_apps()
import json from sonyapilib.device import SonyDevice config_file = 'bluray.json' with open(config_file, 'r') as myfile: data = myfile.read() device = SonyDevice.load_from_json(data) hass_cfg = {} hass_cfg[device.host] = {} hass_cfg[device.host]["device"] = data print(json.dumps(hass_cfg), file=open("sony.conf", "w"))
def test_discovery(self, mock_discover): devices = SonyDevice.discover() self.assertEqual(len(devices), 1) self.assertEqual(devices[0].host, "test")
class SonyMediaPlayerDevice(MediaPlayerDevice): """Representation of a Sony mediaplayer.""" def __init__(self, host, name, pin, mac=None): """ Initialize the Sony mediaplayer device. Mac address is optional but neccessary for wake on LAN """ from sonyapilib.device import SonyDevice self._pin = pin self.sonydevice = SonyDevice(host, name) self._name = name self._state = STATE_OFF self._muted = False self._id = None self._playing = False self.sonydevice.pin = pin self.sonydevice.mac = mac try: self.sonydevice.update_service_urls() self.update() except Exception: # pylint: disable=broad-except self._state = STATE_OFF def update(self): """Update TV info.""" if not self.sonydevice.get_power_status(): self._state = STATE_OFF return self._state = STATE_ON # Retrieve the latest data. try: if self._state == STATE_ON: power_status = self.sonydevice.get_power_status() if power_status: playback_info = self.sonydevice.get_playing_status() if playback_info == "PLAYING": self._state = STATE_PLAYING elif playback_info == "PAUSED_PLAYBACK": self._state = STATE_PAUSED else: self._state = STATE_ON else: self._state = STATE_OFF except Exception as exception_instance: # pylint: disable=broad-except _LOGGER.error(exception_instance) self._state = STATE_OFF @property def name(self): """Return the name of the device.""" return self._name @property def state(self): """Return the state of the device.""" return self._state @property def supported_features(self): """Flag media player features that are supported.""" return SUPPORT_SONY @property def media_title(self): """Title of current playing media.""" # the device used for testing does not send any # information about the media which is played return "" @property def media_content_id(self): """Content ID of current playing media.""" return "" @property def media_duration(self): """Duration of current playing media in seconds.""" return "" def turn_on(self): """Turn the media player on.""" self.sonydevice.power(True) def turn_off(self): """Turn off media player.""" self.sonydevice.power(False) def media_play_pause(self): """Simulate play pause media player.""" if self._playing: self.media_pause() else: self.media_play() def media_play(self): """Send play command.""" self._state = STATE_PLAYING self.sonydevice.play() def media_pause(self): """Send media pause command to media player.""" self._state = STATE_PAUSED self.sonydevice.pause() def media_next_track(self): """Send next track command.""" self.sonydevice.next() def media_previous_track(self): """Send the previous track command.""" self.sonydevice.prev() def media_stop(self): """Send stop command.""" self.sonydevice.stop()