├── .gitignore ├── DaktronicsAllSport5000-RTD-Reference.pdf ├── LICENSE ├── README.md ├── daktronics └── __init__.py ├── examples └── dakexample.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *,cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # dotenv 81 | .env 82 | 83 | # virtualenv 84 | .venv/ 85 | venv/ 86 | ENV/ 87 | 88 | # Spyder project settings 89 | .spyderproject 90 | 91 | # Rope project settings 92 | .ropeproject 93 | ### JetBrains template 94 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 95 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 96 | 97 | # User-specific stuff: 98 | .idea/workspace.xml 99 | .idea/tasks.xml 100 | 101 | # Sensitive or high-churn files: 102 | .idea/dataSources/ 103 | .idea/dataSources.ids 104 | .idea/dataSources.xml 105 | .idea/dataSources.local.xml 106 | .idea/sqlDataSources.xml 107 | .idea/dynamic.xml 108 | .idea/uiDesigner.xml 109 | 110 | # Gradle: 111 | .idea/gradle.xml 112 | .idea/libraries 113 | 114 | # Mongo Explorer plugin: 115 | .idea/mongoSettings.xml 116 | 117 | ## File-based project format: 118 | *.iws 119 | 120 | ## Plugin-specific files: 121 | 122 | # IntelliJ 123 | /out/ 124 | 125 | # mpeltonen/sbt-idea plugin 126 | .idea_modules/ 127 | 128 | # JIRA plugin 129 | atlassian-ide-plugin.xml 130 | 131 | # Crashlytics plugin (for Android Studio and IntelliJ) 132 | com_crashlytics_export_strings.xml 133 | crashlytics.properties 134 | crashlytics-build.properties 135 | fabric.properties 136 | .idea/ 137 | 138 | /testing.py 139 | -------------------------------------------------------------------------------- /DaktronicsAllSport5000-RTD-Reference.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fimion/pydak/7311fce14003b368ca38b534c0e36d859cc21224/DaktronicsAllSport5000-RTD-Reference.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Alex Riviere 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pydak 2 | Python Library for Daktronics AllSport 5000 Scoring Controllers 3 | 4 | Based on the collaboration with [JoshuaCarroll](https://github.com/JoshuaCarroll/scoredata) 5 | 6 | This is being rolled into a single library for easy distribution. -------------------------------------------------------------------------------- /daktronics/__init__.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2016 Alex Riviere 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import serial 24 | import socket 25 | import struct 26 | 27 | dakSports = { 28 | 'auto racing': {}, 29 | 'baseball': {}, 30 | 'basketball': {}, 31 | 'cricket': {}, 32 | 'event counter': {}, 33 | 'football': { 34 | 'dakSize': [1, 295], 35 | 'Main Clock Time [mm:ss/ss.t]': [1, 5], 36 | 'Main Clock Time [mm:ss.t]': [6, 8], 37 | 'Main Clock/Time Out/TOD [mm:ss/ss.t]': [14, 5], 38 | 'Main Clock/Time Out/TOD [mm:ss.t]': [19, 8], 39 | 'Main Clock =0': [27, 1], 40 | 'Main Clock Stopped': [28, 1], 41 | 'Main Clock/Time Out Horn': [29, 1], 42 | 'Main Clock Horn': [30, 1], 43 | 'Time Out Horn': [31, 1], 44 | 'Time Out Time': [32, 8], 45 | 'Time of Day': [40, 8], 46 | 'Home Team Name': [48, 20], 47 | 'Guest Team Name': [68, 20], 48 | 'Home Team Abbreviation': [88, 10], 49 | 'Guest Team Abbreviation': [98, 10], 50 | 'Home Team Score': [108, 4], 51 | 'Guest Team Score': [112, 4], 52 | 'Home Time Outs Left - Full': [116, 2], 53 | 'Home Time Outs Left - Partial': [118, 2], 54 | 'Home Time Outs Left - Television': [120, 2], 55 | 'Home Time Outs Left - Total': [122, 2], 56 | 'Guest Time Outs Left - Full': [124, 2], 57 | 'Guest Time Outs Left - Partial': [126, 2], 58 | 'Guest Time Outs Left - Television': [128, 2], 59 | 'Guest Time Outs Left - Total': [130, 2], 60 | 'Home Time Out Indicator': [132, 1], 61 | 'Home Time Out Text': [133, 4], 62 | 'Guest Time Out Indicator': [137, 1], 63 | 'Guest Time Out Text': [138, 4], 64 | 'Quarter': [142, 2], 65 | 'Quarter Text': [144, 4], 66 | 'Quarter Description': [148, 12], 67 | 'Internal Relay': [160, 1], 68 | 'Ad Panel / Caption Power': [161, 1], 69 | 'Ad Panel / Caption #1': [162, 1], 70 | 'Ad Panel / Caption #2 ': [163, 1], 71 | 'Ad Panel / Caption #3': [164, 1], 72 | 'Ad Panel / Caption #4': [165, 1], 73 | 'Reserved for Future Use': [166, 35], 74 | 'Play Clock Time': [201, 8], 75 | 'Play Clock Horn': [209, 1], 76 | 'Home Possession Indicator': [210, 1], 77 | 'Home Possession Text': [211, 4], 78 | 'Guest Possession Indicator': [215, 1], 79 | 'Guest Possession Text': [216, 4], 80 | 'Ball On': [220, 2], 81 | 'Down': [222, 3], 82 | 'To Go': [225, 2], 83 | 'Home Score - Period 1': [227, 2], 84 | 'Home Score - Period 2': [229, 2], 85 | 'Home Score - Period 3': [231, 2], 86 | 'Home Score - Period 4': [233, 2], 87 | 'Home Score - Period 5': [235, 2], 88 | 'Home Score - Period 6': [237, 2], 89 | 'Home Score - Period 7': [239, 2], 90 | 'Home Score - Period 8': [241, 2], 91 | 'Home Score - Period 9': [243, 2], 92 | 'Home Score - Current Period': [245, 2], 93 | 'Guest Score - Period 1': [247, 2], 94 | 'Guest Score - Period 2': [249, 2], 95 | 'Guest Score - Period 3': [251, 2], 96 | 'Guest Score - Period 4': [253, 2], 97 | 'Guest Score - Period 5': [255, 2], 98 | 'Guest Score - Period 6': [257, 2], 99 | 'Guest Score - Period 7': [259, 2], 100 | 'Guest Score - Period 8': [261, 2], 101 | 'Guest Score - Period 9': [263, 2], 102 | 'Guest Score - Current Period': [265, 2], 103 | 'Home Rushing Yards': [267, 4], 104 | 'Home Passing Yards': [271, 4], 105 | 'Home Total Yards': [275, 4], 106 | 'Guest Rushing Yards': [279, 4], 107 | 'Guest Passing Yards': [283, 4], 108 | 'Guest Total Yards': [287, 4], 109 | 'Home First Downs': [291, 2], 110 | 'Guest First Downs': [293, 2] 111 | }, 112 | 'hockey/lacrosse': { 113 | 'dakSize': [1, 493], 114 | 'Main Clock Time (mm:ss/ss.t )': [1, 5], 115 | '2 Main Clock Time (mm:ss.t )': [6, 8], 116 | '3 Main Clock/Time Out/TOD (mm:ss/ss.t )': [14, 5], 117 | '4 Main Clock/Time Out/TOD (mm:ss.t )': [19, 8], 118 | '5 Main Clock 0': [27, 1], 119 | '6 Main Clock Stopped': [28, 1], 120 | '7 Main Clock/Time Out Horn': [29, 1], 121 | '8 Main Clock Horn': [30, 1], 122 | '9 Time Out Horn': [31, 1], 123 | '10 Time Out Time (mm:ss)': [32, 8], 124 | '11 Time of Day (hh:mm:ss)': [40, 8], 125 | '12 Home Team Name': [48, 20], 126 | '13 Guest Team Name': [68, 20], 127 | '14 Home Team Abbreviation': [88, 10], 128 | '15 Guest Team Abbreviation': [98, 10], 129 | '16 Home Team Score': [108, 4], 130 | '17 Guest Team Score': [112, 4], 131 | '18 Home Time Outs Left - Full': [116, 2], 132 | '19 Home Time Outs Left - Partial': [118, 2], 133 | '20 Home Time Outs Left - Television': [120, 2], 134 | '21 Home Time Outs Left - Total': [122, 2], 135 | '22 Guest Time Outs Left - Full': [124, 2], 136 | '23 Guest Time Outs Left - Partial': [126, 2], 137 | '24 Guest Time Outs Left - Television': [128, 2], 138 | '25 Guest Time Outs Left - Total': [130, 2], 139 | '26 Home Time Out Indicator': [132, 1], 140 | '27 Home Time Out Text': [133, 4], 141 | '28 Guest Time Out Indicator': [137, 1], 142 | '29 Guest Time Out Text': [138, 4], 143 | '30 Period': [142, 2], 144 | '31 Period Text': [144, 4], 145 | '32 Period Description': [148, 12], 146 | '33 Internal Relay': [160, 1], 147 | '34 Ad Panel / Caption Power': [161, 1], 148 | '35 Ad Panel / Caption #1': [162, 1], 149 | '36 Ad Panel / Caption #2': [163, 1], 150 | '37 Ad Panel / Caption #3': [164, 1], 151 | '38 Ad Panel / Caption #4': [165, 1], 152 | '39 Reserved for Future Use': [166, 35], 153 | '40 Shot Clock Time (mm:ss)': [201, 8], 154 | '41 Shot Clock Horn': [209, 1], 155 | '42 Inverse Time Clock (mm:ss)': [210, 8], 156 | '43 Inverse/Main/Time Out/TOD (mm:ss)': [218, 8], 157 | '44 Home Player #1-Number': [226, 2], 158 | '45 Home Player #1-Penalty Time (mm:ss)': [228, 8], 159 | '46 Home Player #2-Number': [236, 2], 160 | '47 Home Player #2-Penalty Time (mm:ss)': [238, 8], 161 | '48 Home Player #3-Number': [246, 2], 162 | '49 Home Player #3-Penalty Time (mm:ss)': [248, 8], 163 | '50 Home Player #4-Number': [256, 2], 164 | '51 Home Player #4-Penalty Time (mm:ss)': [258, 8], 165 | '52 Home Player #5-Number': [266, 2], 166 | '53 Home Player #5-Penalty Time (mm:ss)': [268, 8], 167 | '54 Home Player #6-Number': [276, 2], 168 | '55 Home Player #6-Penalty Time (mm:ss)': [278, 8], 169 | '56 Guest Player #1-Number': [286, 2], 170 | '57 Guest Player #1-Penalty Time (mm:ss)': [288, 8], 171 | '58 Guest Player #2-Number': [296, 2], 172 | '59 Guest Player #2-Penalty Time (mm:ss)': [298, 8], 173 | '60 Guest Player #3-Number': [306, 2], 174 | '61 Guest Player #3-Penalty Time (mm:ss)': [308, 8], 175 | '62 Guest Player #4-Number': [316, 2], 176 | '63 Guest Player #4-Penalty Time (mm:ss)': [318, 8], 177 | '64 Guest Player #5-Number': [326, 2], 178 | '65 Guest Player #5-Penalty Time (mm:ss)': [328, 8], 179 | '66 Guest Player #6-Number': [336, 2], 180 | '67 Guest Player #6-Penalty Time (mm:ss)': [338, 8], 181 | '68 Home Penalty Indicator': [346, 1], 182 | '69 Home Penalty Text': [347, 7], 183 | '70 Guest Penalty Indicator': [354, 1], 184 | '71 Guest Penalty Text': [355, 7], 185 | '72 Home Score - Period 1': [362, 2], 186 | '73 Home Score - Period 2': [364, 2], 187 | '74 Home Score - Period 3': [366, 2], 188 | '75 Home Score - Period 4': [368, 2], 189 | '76 Home Score - Period 5': [370, 2], 190 | '77 Home Score - Period 6': [372, 2], 191 | '78 Home Score - Period 7': [374, 2], 192 | '79 Home Score - Period 8': [376, 2], 193 | '80 Home Score - Period 9': [378, 2], 194 | '81 Home Score - Current Period': [380, 2], 195 | '82 Guest Score - Period 1': [382, 2], 196 | '83 Guest Score - Period 2': [384, 2], 197 | '84 Guest Score - Period 3': [386, 2], 198 | '85 Guest Score - Period 4': [388, 2], 199 | '86 Guest Score - Period 5': [390, 2], 200 | '87 Guest Score - Period 6': [392, 2], 201 | '88 Guest Score - Period 7': [394, 2], 202 | '89 Guest Score - Period 8': [396, 2], 203 | '90 Guest Score - Period 9': [398, 2], 204 | '91 Guest Score - Current Period': [400, 2], 205 | '92 Home Shots On Goal - Period 1': [402, 2], 206 | '93 Home Shots On Goal - Period 2': [404, 2], 207 | '94 Home Shots On Goal - Period 3': [406, 2], 208 | '95 Home Shots On Goal - Period 4': [408, 2], 209 | '96 Home Shots On Goal - Period 5': [410, 2], 210 | '97 Home Shots On Goal - Period 6': [412, 2], 211 | '98 Home Shots On Goal - Period 7': [414, 2], 212 | '99 Home Shots On Goal - Period 8': [416, 2], 213 | '100 Home Shots On Goal - Period 9': [418, 2], 214 | '101 Home Shots On Goal - Current': [420, 2], 215 | '102 Home Shots On Goal - Total': [422, 3], 216 | '103 Home Saves - Period 1': [425, 2], 217 | '104 Home Saves - Period 2': [427, 2], 218 | '105 Home Saves - Period 3': [429, 2], 219 | '106 Home Saves - Period 4': [431, 2], 220 | '107 Home Saves - Period 5': [433, 2], 221 | '108 Home Saves - Period 6': [435, 2], 222 | '109 Home Saves - Period 7': [437, 2], 223 | '110 Home Saves - Period 8': [439, 2], 224 | '111 Home Saves - Period 9': [441, 2], 225 | '112 Home Saves - Current': [443, 2], 226 | '113 Home Saves - Total': [445, 3], 227 | '114 Guest Shots On Goal - Period 1': [448, 2], 228 | '115 Guest Shots On Goal - Period 2': [450, 2], 229 | '116 Guest Shots On Goal - Period 3': [452, 2], 230 | '117 Guest Shots On Goal - Period 4': [454, 2], 231 | '118 Guest Shots On Goal - Period 5': [456, 2], 232 | '119 Guest Shots On Goal - Period 6': [458, 2], 233 | '120 Guest Shots On Goal - Period 7': [460, 2], 234 | '121 Guest Shots On Goal - Period 8': [462, 2], 235 | '122 Guest Shots On Goal - Period 9': [464, 2], 236 | '123 Guest Shots On Goal - Current': [466, 2], 237 | '124 Guest Shots On Goal - Total': [468, 3], 238 | '125 Guest Saves - Period 1': [471, 2], 239 | '126 Guest Saves - Period 2': [473, 2], 240 | '127 Guest Saves - Period 3': [475, 2], 241 | '128 Guest Saves - Period 4': [477, 2], 242 | '129 Guest Saves - Period 5': [479, 2], 243 | '130 Guest Saves - Period 6': [481, 2], 244 | '131 Guest Saves - Period 7': [483, 2], 245 | '132 Guest Saves - Period 8': [485, 2], 246 | '133 Guest Saves - Period 9': [487, 2], 247 | '134 Guest Saves - Current': [489, 2], 248 | '135 Guest Saves - Total': [491, 3], 249 | }, 250 | 'judo': {}, 251 | 'karate': {}, 252 | 'lane timer': {}, 253 | 'pitch and speed': {}, 254 | 'rodeo': {}, 255 | 'soccer': {}, 256 | 'strike out count': {}, 257 | 'taekwondo': {}, 258 | 'tennis': {}, 259 | 'track': {}, 260 | 'volleyball': {}, 261 | 'waterpolo': {}, 262 | 'wrestling': {} 263 | } 264 | 265 | DAKUDP_IP = "224.51.105.104" 266 | 267 | 268 | class DakSerial(object): 269 | def __init__(self, data=None): 270 | if type(data) is serial.Serial: 271 | self.data = data 272 | elif type(data) is str: 273 | self.data = serial.Serial(data, baudrate=19200, timeout=1) 274 | else: 275 | self.data = serial.Serial("COM1", baudrate=19200, timeout=1) 276 | 277 | def read(self): 278 | rtd = b'' 279 | c = b'' 280 | while c != b'\x16': 281 | c = self.data.read() 282 | c = b'\x16' 283 | while c != b'\x17': 284 | c = self.data.read() 285 | rtd += c 286 | return rtd 287 | 288 | 289 | class DakUDP(object): 290 | def __init__(self, data=21000): 291 | self.data = None 292 | self.data = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 293 | self.data.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 294 | self.data.bind(('', data)) 295 | mreq = struct.pack("=4sl", socket.inet_aton(DAKUDP_IP), socket.INADDR_ANY) 296 | self.data.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) 297 | 298 | def read(self): 299 | return self.data.recv(1024) 300 | 301 | 302 | class Daktronics(object): 303 | def __init__(self, sport, data): 304 | self.dakrtd = data 305 | self.header = b'' 306 | self.code = b'' 307 | self.rtd = b'' 308 | self.checksum = b'' 309 | self.text = b'' 310 | self.sport = dakSports[sport] 311 | self.dakString = " " * self.sport['dakSize'][1] 312 | 313 | def update(self): 314 | self.rtd = self.dakrtd.read() 315 | 316 | self.header = self.rtd.partition(b'\x16')[2].partition(b'\x01')[0] 317 | self.code = self.rtd.partition(b'\x01')[2].partition(b'\x02')[0].partition(b'\x04')[0] 318 | self.text = self.rtd.partition(b'\x02')[2].partition(b'\x04')[0] 319 | self.checksum = self.rtd.partition(b'\x04')[2].partition(b'\x17')[0] 320 | 321 | code = self.code.decode() 322 | code = code[-4:] 323 | text = self.text.decode() 324 | self.dakString = self.dakString[:int(code)] + text + self.dakString[int(code) + len(text):] 325 | 326 | def __getitem__(self, gikey): 327 | if gikey in self.sport: 328 | return self.dakString[self.sport[gikey][0] - 1:self.sport[gikey][1] + self.sport[gikey][0] - 1] 329 | return "" 330 | -------------------------------------------------------------------------------- /examples/dakexample.py: -------------------------------------------------------------------------------- 1 | from daktronics import DakUDP, Daktronics 2 | 3 | if __name__ == '__main__': 4 | print("UDP MULTICAST 21000") 5 | dak_data = DakUDP(21000) 6 | dak = Daktronics("hockey/lacrosse", dak_data) 7 | while True: 8 | dak.update() 9 | print("--------------------------------------------------------------") 10 | print(dak['Main Clock Time (mm:ss/ss.t )']) 11 | print(dak['Home Team Name'], dak['Home Team Score']) 12 | print(dak['Guest Team Name'], dak['Guest Team Score']) 13 | print("--------------------------------------------------------------") 14 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name='pydak', 5 | version='0.2', 6 | packages=['daktronics'], 7 | install_requires=['pyserial'], 8 | url='https://github.com/fimion/pydak', 9 | license='MIT', 10 | author='Alex Riviere', 11 | author_email='fimion@gmail.com', 12 | description='Python Library for Daktronics AllSport 5000 Scoring Controllers' 13 | ) 14 | --------------------------------------------------------------------------------