async def run(self): power = self.device.power.power_state == PowerState.On playing = await self.device.metadata.playing() if self.name == "appletv-office": print(self.name, "playing\n", playing) app = "None" try: app = self.device.metadata.app.name # print(app) except Exception: app = "None" pass # print(self.name, "no app") print("\n"); print("\n"); print(self.name, "Power", power, "App", app) #### ARTWORK artwork = await self.device.metadata.artwork(300, 300) if artwork: try: tmp_filename = "/tmp/{}".format(self.name) file = open(tmp_filename, "wb") file.write(artwork.bytes) file.close() file = open(tmp_filename, "rb") image_data_binary = file.read() file.close() try: os.remove(tmp_filename) finally: pass artwork = base64.b64encode(image_data_binary).decode("ascii") except Exception as err: artwork = None o = { "power": power, "app": app, "mediaType": convert.media_type_str(playing.media_type), "deviceState": convert.device_state_str(playing.device_state), "title": playing.title, "artist": playing.artist, "album": playing.album, "genre": playing.genre, "position": playing.position, "total_time": playing.total_time, "repeat": convert.repeat_str(playing.repeat), "shuffle": convert.shuffle_str(playing.shuffle), } if o != self.state: await self.publish("info", json.dumps(o)) o["artwork"] = artwork await self.set_state(o)
def test_device_state_str(): assert "Idle" == convert.device_state_str(DeviceState.Idle) assert "Loading" == convert.device_state_str(DeviceState.Loading) assert "Stopped" == convert.device_state_str(DeviceState.Stopped) assert "Paused" == convert.device_state_str(DeviceState.Paused) assert "Playing" == convert.device_state_str(DeviceState.Playing) assert "Seeking" == convert.device_state_str(DeviceState.Seeking)
def test_device_state_str(self): self.assertEqual("Idle", convert.device_state_str(DeviceState.Idle)) self.assertEqual("Loading", convert.device_state_str(DeviceState.Loading)) self.assertEqual("Stopped", convert.device_state_str(DeviceState.Stopped)) self.assertEqual("Paused", convert.device_state_str(DeviceState.Paused)) self.assertEqual("Playing", convert.device_state_str(DeviceState.Playing)) self.assertEqual("Seeking", convert.device_state_str(DeviceState.Seeking))
def test_device_state_str(self): self.assertEqual('Idle', convert.device_state_str(DeviceState.Idle)) self.assertEqual('Loading', convert.device_state_str(DeviceState.Loading)) self.assertEqual('Stopped', convert.device_state_str(DeviceState.Stopped)) self.assertEqual('Paused', convert.device_state_str(DeviceState.Paused)) self.assertEqual('Playing', convert.device_state_str(DeviceState.Playing)) self.assertEqual('Seeking', convert.device_state_str(DeviceState.Seeking))
def __str__(self) -> str: """Convert this playing object to a readable string.""" output = [] output.append( " Media type: {0}".format(convert.media_type_str(self.media_type)) ) output.append( "Device state: {0}".format(convert.device_state_str(self.device_state)) ) if self.title is not None: output.append(" Title: {0}".format(self.title)) if self.artist is not None: output.append(" Artist: {0}".format(self.artist)) if self.album is not None: output.append(" Album: {0}".format(self.album)) if self.genre is not None: output.append(" Genre: {0}".format(self.genre)) position = self.position total_time = self.total_time if position is not None and total_time is not None and total_time != 0: output.append( " Position: {0}/{1}s ({2:.1%})".format( position, total_time, float(position) / float(total_time) ) ) elif position is not None and position != 0: output.append(" Position: {0}s".format(position)) elif total_time is not None and position != 0: output.append(" Total time: {0}s".format(total_time)) if self.repeat is not None: output.append(" Repeat: {0}".format(convert.repeat_str(self.repeat))) if self.shuffle is not None: output.append(" Shuffle: {0}".format(convert.shuffle_str(self.shuffle))) return "\n".join(output)
def test_device_state_str(device_state, output): assert convert.device_state_str(device_state) == output
async def main(): global config global atvs global config_map global device_map global atv_map print("Getting global Config") mongo = MongoClient(MONGO_HOST) db = mongo["settings"] collection = db.config raw = collection.find_one({"_id": "config"}) for entry in raw["appletv"]["devices"]: ip = socket.gethostbyname(entry['device']) config_map[ip] = entry print("entry", entry) print(" config", ip, entry['name'], entry['device']) config.append(entry) device_map[entry['device']] = entry # config = get_config() # print("config_map", config_map.keys()) # devices = await scan() # get ATVs loop = asyncio.get_event_loop() atv_map = {} scanning = True while scanning: scanning = False print("Scanning for apple tvs...") devices = await pyatv.scan(loop, timeout=5) # print(" config_map", config_map.keys()) if not devices: print("No apple tvs found", file=sys.stderr) scanning = True else: for atv in devices: ip = str(atv.address) atv_map[ip] = atv print(" found device", atv.address, atv.name) for key in config_map.keys(): # print('key', key, config_map[key], atv_map[key]); if key in atv_map.keys(): atv_map[key].set_credentials( Protocol.AirPlay, config_map[key]["credentials"]) config_map[key]["appletv"] = atv_map[key] else: print(" ... key ", key, "not in atv_map") scanning = True break print("Scan complete!") for device in config: # print(".\n") # print(".\n") # print(".\n") # print(".\n") # print(device) # print(".\n") # print(".\n") # print(".\n") # print(".\n") # atv = device['atv'] # print("found", device.name, found); device['state'] = { "power": None, "app": None, "mediaType": None, "deviceState": None, "title": None, "artist": None, "album": None, "genre": None, "position": None, "total_time": None, "repeat": None, "shuffle": None, "artwork": None, "contentIdentifier": None, "season_number": None, "episode_number": None, "series_name": None, } try: app = "None" # print("ATV Connecting to ", device['name']) atv = await pyatv.connect(device['appletv'], loop) device['atv'] = atv # print("Connected to ATV") topic = "appletv/{}/set/command".format(device['device']) print("subscribe", topic) MQTT.subscribe(topic) # except Exception as err: finally: pass # print("Exception err {}".format(err)); # continue # found['atv'] = atv # fn = found['device'] # print("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz found", found, fn) # atv_map[fn] = atv # atv_map[found[device]] = atv # atvs.append({ # "config": found, # "device": device, # "atv": atv, # }) while True: for item in config: # print("item", item) device = item['device'] name = item['name'] atv = item['atv'] conf = item # print("loop", name) app = "None" try: app = atv.metadata.app.name # print(app) except Exception: app = "None" power = atv.power.power_state == PowerState.On playing = await atv.metadata.playing() artwork = await atv.metadata.artwork(300, 300) if artwork: try: tmp_filename = "/tmp/{}".format(name) file = open(tmp_filename, "wb") file.write(artwork.bytes) file.close() file = open(tmp_filename, "rb") image_data_binary = file.read() file.close() try: os.remove(tmp_filename) finally: pass artwork = base64.b64encode(image_data_binary).decode( "ascii") except Exception as err: artwork = None o = { "power": power, "app": app, "mediaType": convert.media_type_str(playing.media_type), "deviceState": convert.device_state_str(playing.device_state), "title": playing.title, "artist": playing.artist, "album": playing.album, "genre": playing.genre, "position": playing.position, "total_time": playing.total_time, "repeat": convert.repeat_str(playing.repeat), "shuffle": convert.shuffle_str(playing.shuffle), "artwork": artwork, "seasonNumber": playing.season_number if hasattr(playing, 'season_number') else None, "episodeNumber": playing.episode_number if hasattr(playing, 'episode_number') else None, "seriesName": playing.series_name if hasattr(playing, 'series_name') else None, "contentIdentifier": playing.content_identifier if hasattr(playing, 'content_identifier') else None, } # try: # o["contentIdentifier"] = playing.content_identifier # finally: # pass # try: # o["season_number"] = playing.season_number # finally: # pass # try: # o["episode_number"] = playing.episode_number # finally: # pass # try: # o["series_name"] = playing.series_name # finally: # pass # if convert.device_state_str(playing.device_state) == "Playing": # print(playing.__dict__) # print("") if o != conf['state']: topic = "appletv/{}/status/{}".format(conf['device'], "info") # print(topic, json.dumps(o)[:40]) MQTT.publish(topic, json.dumps(o), retain=True) for attr, value in o.items(): # print("attr", attr, "value", value, conf['state'][attr]) try: if value != conf["state"][attr]: topic = "appletv/{}/status/{}".format( conf['device'], attr) # if name == "Office": # print(name, "publish", topic, value) conf['state'][attr] = o[attr] MQTT.publish(topic, o[attr], retain=True) except Exception as ex: # try: # MQTT.publish(topic, value, retain=True) # finally: pass # process queue # print("process queue") while True: try: cmd = command_queue.pop() print("dequeue command", cmd) device = cmd['device'] message = cmd['command'] print("command", device, message) if device == "reset": print("RECEIVED RESET. EXITING...\n\n\n") os._exit(0) atv = device_map[device]['atv'] if message == "STOP": await atv.remote_control.right() elif message == "MENU": await atv.remote_control.menu() elif message == "SUSPEND": await atv.remote_control.home() elif message == "HOME": await atv.remote_control.home() elif message == "POWER": await atv.power.turn_off() elif message == "UP": await atv.remote_control.up() elif message == "DOWN": await atv.remote_control.down() elif message == "LEFT": await atv.remote_control.left() elif message == "RIGHT": await atv.remote_control.right() elif message == "SELECT": await atv.remote_control.select() elif message == "PAUSE": await atv.remote_control.pause() elif message == "PLAY": await atv.remote_control.play() elif message == "BEGINREWIND": await atv.remote_control.skip_backward() elif message == "BEGINFORWARD": await atv.remote_control.skip_forward() else: print("invalid command", message) except Exception: break await asyncio.sleep(1)
def test_playing_media_type_and_playstate(): out = str( Playing(media_type=MediaType.Video, device_state=DeviceState.Playing)) assert convert.media_type_str(MediaType.Video) in out assert convert.device_state_str(DeviceState.Playing) in out
async def main(): global config global atvs mongo = MongoClient(MONGO_HOST) db = mongo["settings"] collection = db.config raw = collection.find_one({"_id": "config"}) for entry in raw["appletv"]["devices"]: # print("entry", entry["device"], entry) config.append(entry) loop = asyncio.get_event_loop() devices = await pyatv.scan(loop, timeout=5) if not devices: print("No apple tvs found", file=sys.stderr) return for device in devices: print(device) print("\n") found = find_config(device.name) if found: topic = "appletv/{}/set/command".format(device.name) MQTT.subscribe(topic) found['state'] = { "power": None, "app": None, "mediaType": None, "deviceState": None, "title": None, "artist": None, "album": None, "genre": None, "position": None, "total_time": None, "repeat": None, "shuffle": None, "artwork": None, }; # connected = False # while not connected: # try: # print("CONNECTING TO ", device.address, device.name) # atv = await pyatv.connect(device, loop) # print(" -> CONNECTED", device.address) # connected = True # except Exception: # await atv.close(loop) # pass atv = device atvs.append({ "config": found, "device": device, "atv": atv, }) while True: for item in atvs: device = item['device'] name = device.name atv = item['atv'] config = item['config'] app = "None" try: app = atv.metadata.app.name # print(app) except Exception: app = "None" power = atv.power.power_state == PowerState.On playing = await atv.metadata.playing() o = { "power": power, "app": app, "mediaType": convert.media_type_str(playing.media_type), "deviceState": convert.device_state_str(playing.device_state), "title": playing.title, "artist": playing.artist, "album": playing.album, "genre": playing.genre, "position": playing.position, "total_time": playing.total_time, "repeat": convert.repeat_str(playing.repeat), "shuffle": convert.shuffle_str(playing.shuffle), } if o != config['state']: MQTT.publish("info", json.dumps(o), retain=True) artwork = await atv.metadata.artwork(300, 300) if artwork: try: tmp_filename = "/tmp/{}".format(name) file = open(tmp_filename, "wb") file.write(artwork.bytes) file.close() file = open(tmp_filename, "rb") image_data_binary = file.read() file.close() try: os.remove(tmp_filename) finally: pass artwork = base64.b64encode(image_data_binary).decode("ascii") except Exception as err: artwork = None o['artwork'] = artwork for attr, value in o.items(): # print("attr", attr, "value", value, config['state'][attr]) if value != config["state"][attr]: topic = "appletv/{}/status/{}".format(config['device'], attr) if device.name == "Office": print(device.name, "publish", topic, value) config['state'][attr] = o[attr] MQTT.publish(topic, value, retain=True) await asyncio.sleep(1)
def test_playing_media_type_and_playstate(self): out = str(PlayingDummy()) self.assertIn(convert.media_type_str(MediaType.Video), out) self.assertIn(convert.device_state_str(DeviceState.Playing), out)
def test_unsupported_device_state_str(): assert "Unsupported" == convert.device_state_str(999)
def test_unsupported_device_state_str(self): self.assertEqual("Unsupported", convert.device_state_str(999))