├── DirectPy.py ├── README.md └── setup.py /DirectPy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import requests 3 | 4 | 5 | class DIRECTV: 6 | """DirectPy.py by Eric Walters (github.com/sentry07) 7 | 8 | Control a DirecTV receiver over the network using 9 | DirecTV's SHEF protocol. For more information on 10 | enabling the SHEF interface, please see this PDF: 11 | https://www.satinstalltraining.com/homeautomation/DTV-MD-0359-DIRECTV_SHEF_Command_Set-V1.3.C.pdf 12 | 13 | The clientAddr parameter of the class is used for 14 | Genie systems that have a server receiver and client 15 | receivers. To control a client receiver, you must 16 | know the MAC address and reference it without colons. 17 | EX: DIRECTV('192.168.1.10',clientAddr='000A959D6816') 18 | """ 19 | def __init__(self, ip, port=8080, clientAddr='0', determine_state=True): 20 | self.ip = ip 21 | self.port = port 22 | self.clientAddr = clientAddr 23 | self.standby = False 24 | self.channel = '0' 25 | self.valid_keys = ['power', 'poweron', 'poweroff', 'format', 'pause', 26 | 'rew', 'replay', 'stop', 'advance', 'ffwd', 27 | 'record', 'play', 'guide', 'active', 'list', 'exit', 28 | 'back', 'menu', 'info', 'up', 'down', 'left', 29 | 'right', 'select', 'red', 'green', 'yellow', 'blue', 30 | 'chanup', 'chandown', 'prev', '0', '1', '2', '3', 31 | '4', '5', '6', '7', '8', '9', 'dash', 'enter'] 32 | 33 | self.base_url = 'http://%s:%s' % (ip, port) 34 | 35 | if determine_state: 36 | self.get_standby() 37 | if not self.standby: 38 | self.get_tuned() 39 | 40 | @staticmethod 41 | def _parse_channel(channel): 42 | """Return major and minor channel numbers for given channel""" 43 | try: 44 | major, minor = channel.split('-') 45 | except ValueError: 46 | major = channel 47 | minor = 65535 48 | 49 | return major, minor 50 | 51 | @staticmethod 52 | def _combine_channel(major, minor): 53 | """Return the combined channel number. If minor == 65535, there is no 54 | 55 | minor channel number.""" 56 | if minor == 65535: 57 | return str(major) 58 | else: 59 | return '%d-%d' % (major, minor) 60 | 61 | def get_standby(self): 62 | """Return standby status of the receiver.""" 63 | jResp = requests.get('%s/info/mode?clientAddr=%s' % 64 | (self.base_url, self.clientAddr)).json() 65 | 66 | """Handle clientAddrs that are offline/not reporting for some reason""" 67 | if jResp['status']['code'] == 403: 68 | self.standby = 1 69 | else: 70 | self.standby = (jResp['mode'] == 1) 71 | 72 | return self.standby 73 | 74 | def get_channel(self, channel: "'###' or '###-#'"): 75 | """Return program information for a channel.""" 76 | if not type(channel) is str: 77 | raise TypeError('Channel should be a string') 78 | major, minor = self._parse_channel(channel) 79 | jResp = requests.get( 80 | '%s/tv/getProgInfo?major=%s&minor=%s&clientAddr=%s' % 81 | (self.base_url, major, minor, self.clientAddr)).json() 82 | 83 | return jResp 84 | 85 | def get_tuned(self): 86 | """Returns the channel and program information of the current 87 | 88 | channel.""" 89 | jResp = requests.get( 90 | '%s/tv/getTuned?clientAddr=%s' % 91 | (self.base_url, self.clientAddr)).json() 92 | if jResp['status']['code'] == 200: 93 | self.channel = self._combine_channel(jResp['major'], 94 | jResp['minor']) 95 | 96 | return jResp 97 | 98 | def tune_channel(self, channel: "'###' or '###-#'"): 99 | """Change the channel on the receiver.""" 100 | if not type(channel) is str: 101 | raise TypeError('Channel should be a string') 102 | major, minor = self._parse_channel(channel) 103 | 104 | jResp = requests.get( 105 | '%s/tv/tune?major=%s&minor=%s&clientAddr=%s' % 106 | (self.base_url, major, minor, self.clientAddr)).json() 107 | if jResp['status']['code'] == 200: 108 | self.channel = channel 109 | 110 | return jResp 111 | 112 | def key_press(self, key: str): 113 | """Emulate pressing a key on the remote. See help() for supported keys. 114 | 115 | Supported keys: power, poweron, poweroff, format, 116 | pause, rew, replay, stop, advance, ffwd, record, 117 | play, guide, active, list, exit, back, menu, info, 118 | up, down, left, right, select, red, green, yellow, 119 | blue, chanup, chandown, prev, 0, 1, 2, 3, 4, 5, 120 | 6, 7, 8, 9, dash, enter 121 | """ 122 | if not type(key) is str: 123 | raise TypeError('Key should be a string') 124 | if not key.lower() in self.valid_keys: 125 | raise ValueError('Invalid key: ' + key) 126 | 127 | jResp = requests.get( 128 | '%s/remote/processKey?key=%s&hold=keyPress&clientAddr=%s' % 129 | (self.base_url, key, self.clientAddr)).json() 130 | 131 | return jResp 132 | 133 | def get_locations(self): 134 | """Returns the clientAddr for all devices.""" 135 | 136 | jResp = requests.get('%s/info/getLocations' % (self.base_url)).json() 137 | 138 | return jResp 139 | 140 | def get_version(self): 141 | """Returns the access card ID, received ID, STB software version, 142 | 143 | system time ,and version of current implementation.""" 144 | 145 | jResp = requests.get('%s/info/getVersion' % (self.base_url)).json() 146 | 147 | return jResp 148 | 149 | def get_serial_num(self): 150 | """Returns the serial number.""" 151 | 152 | jResp = requests.get('%s/info/getSerialNum' % (self.base_url)).json() 153 | 154 | return jResp 155 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DirectPy 2 | ======== 3 | 4 | A Python 2.5+/3 library for interacting with DirecTV receivers. For more information on setting up your receiver to use the API, please see: 5 | http://forums.solidsignal.com/docs/DTV-MD-0359-DIRECTV_SHEF_Command_Set-V1.3.C.pdf 6 | 7 | This class import provides basic functions for controlling a DirecTV receiver, either by setting its 8 | channel directly or emulating remote button presses, as well as the ability to retrieve information 9 | from the receiver about its status, current channel, and program information. 10 | 11 | Example use: 12 | ============ 13 | from DirectPy import DIRECTV 14 | 15 | \# Initiate a new object using the IP address of the receiver 16 | dtv = DIRECTV('192.168.1.10') 17 | 18 | \# Initiate a new object using the IP address of the receiver and the MAC address of the client 19 | dtv = DIRECTV('192.168.1.10',clientAddr='000A959D6816') 20 | 21 | \# Emulate pressing the power on button 22 | dtv.key_press('poweron') 23 | 24 | \# Get the currently tuned channel 25 | dtv.get_tuned() 26 | 27 | \# Set the channel to 249 28 | dtv.tune_channel('249') 29 | 30 | \# Get information about the program that is on channel 264 31 | dtv.get_channel('264') 32 | 33 | \# Emulate pressing the power off button 34 | dtv.key_press('poweroff') 35 | 36 | \# Retrieve the different RVU's attached 37 | dtv.get_locations() 38 | 39 | \# Retrieve access card ID, receiver ID, STB software version, system time, and version of current implementation 40 | dtv.get_version() 41 | 42 | \# Retrieve serial number 43 | dtv.get_serialnum() 44 | 45 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup(name='directpy', 4 | version='0.7', 5 | description='A python library for interacting with DirecTV receivers', 6 | url='http://github.com/sentry07/DirectPy', 7 | author='Eric Walters', 8 | author_email='sentry07@gmail.com', 9 | license='MIT', 10 | py_modules=['DirectPy']) 11 | --------------------------------------------------------------------------------