├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── Adafruit_MAX31855 ├── MAX31855.py └── __init__.py ├── LICENSE ├── README.md ├── examples └── simpletest.py ├── ez_setup.py └── setup.py /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for opening an issue on an Adafruit Python library repository. To 2 | improve the speed of resolution please review the following guidelines and 3 | common troubleshooting steps below before creating the issue: 4 | 5 | - **Do not use GitHub issues for troubleshooting projects and issues.** Instead use 6 | the forums at http://forums.adafruit.com to ask questions and troubleshoot why 7 | something isn't working as expected. In many cases the problem is a common issue 8 | that you will more quickly receive help from the forum community. GitHub issues 9 | are meant for known defects in the code. If you don't know if there is a defect 10 | in the code then start with troubleshooting on the forum first. 11 | 12 | - **If following a tutorial or guide be sure you didn't miss a step.** Carefully 13 | check all of the steps and commands to run have been followed. Consult the 14 | forum if you're unsure or have questions about steps in a guide/tutorial. 15 | 16 | - **For Python/Raspberry Pi projects check these very common issues to ensure they don't apply**: 17 | 18 | - If you are receiving an **ImportError: No module named...** error then a 19 | library the code depends on is not installed. Check the tutorial/guide or 20 | README to ensure you have installed the necessary libraries. Usually the 21 | missing library can be installed with the `pip` tool, but check the tutorial/guide 22 | for the exact command. 23 | 24 | - **Be sure you are supplying adequate power to the board.** Check the specs of 25 | your board and power in an external power supply. In many cases just 26 | plugging a board into your computer is not enough to power it and other 27 | peripherals. 28 | 29 | - **Double check all soldering joints and connections.** Flakey connections 30 | cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. 31 | 32 | If you're sure this issue is a defect in the code and checked the steps above 33 | please fill in the following fields to provide enough troubleshooting information. 34 | You may delete the guideline and text above to just leave the following details: 35 | 36 | - Platform/operating system (i.e. Raspberry Pi with Raspbian operating system, 37 | Windows 32-bit, Windows 64-bit, Mac OSX 64-bit, etc.): **INSERT PLATFORM/OPERATING 38 | SYSTEM HERE** 39 | 40 | - Python version (run `python -version` or `python3 -version`): **INSERT PYTHON 41 | VERSION HERE** 42 | 43 | - Error message you are receiving, including any Python exception traces: **INSERT 44 | ERROR MESAGE/EXCEPTION TRACES HERE*** 45 | 46 | - List the steps to reproduce the problem below (if possible attach code or commands 47 | to run): **LIST REPRO STEPS BELOW** 48 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for creating a pull request to contribute to Adafruit's GitHub code! 2 | Before you open the request please review the following guidelines and tips to 3 | help it be more easily integrated: 4 | 5 | - **Describe the scope of your change--i.e. what the change does and what parts 6 | of the code were modified.** This will help us understand any risks of integrating 7 | the code. 8 | 9 | - **Describe any known limitations with your change.** For example if the change 10 | doesn't apply to a supported platform of the library please mention it. 11 | 12 | - **Please run any tests or examples that can exercise your modified code.** We 13 | strive to not break users of the code and running tests/examples helps with this 14 | process. 15 | 16 | Thank you again for contributing! We will try to test and integrate the change 17 | as soon as we can, but be aware we have many GitHub repositories to manage and 18 | can't immediately respond to every request. There is no need to bump or check in 19 | on a pull request (it will clutter the discussion of the request). 20 | 21 | Also don't be worried if the request is closed or not integrated--sometimes the 22 | priorities of Adafruit's GitHub code (education, ease of use) might not match the 23 | priorities of the pull request. Don't fret, the open source community thrives on 24 | forks and GitHub makes it easy to keep your changes in a forked repo. 25 | 26 | After reviewing the guidelines above you can delete this text from the pull request. 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | *.egg-info 4 | *.pyc 5 | -------------------------------------------------------------------------------- /Adafruit_MAX31855/MAX31855.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 Adafruit Industries 2 | # Author: Tony DiCola 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | import logging 22 | import math 23 | 24 | import Adafruit_GPIO as GPIO 25 | import Adafruit_GPIO.SPI as SPI 26 | 27 | 28 | class MAX31855(object): 29 | """Class to represent an Adafruit MAX31855 thermocouple temperature 30 | measurement board. 31 | """ 32 | 33 | def __init__(self, clk=None, cs=None, do=None, spi=None, gpio=None): 34 | """Initialize MAX31855 device with software SPI on the specified CLK, 35 | CS, and DO pins. Alternatively can specify hardware SPI by sending an 36 | Adafruit_GPIO.SPI.SpiDev device in the spi parameter. 37 | """ 38 | self._logger = logging.getLogger('Adafruit_MAX31855.MAX31855') 39 | self._spi = None 40 | # Handle hardware SPI 41 | if spi is not None: 42 | self._logger.debug('Using hardware SPI') 43 | self._spi = spi 44 | elif clk is not None and cs is not None and do is not None: 45 | self._logger.debug('Using software SPI') 46 | # Default to platform GPIO if not provided. 47 | if gpio is None: 48 | gpio = GPIO.get_platform_gpio() 49 | self._spi = SPI.BitBang(gpio, clk, None, do, cs) 50 | else: 51 | raise ValueError('Must specify either spi for for hardware SPI or clk, cs, and do for softwrare SPI!') 52 | self._spi.set_clock_hz(5000000) 53 | self._spi.set_mode(0) 54 | self._spi.set_bit_order(SPI.MSBFIRST) 55 | 56 | def readInternalC(self): 57 | """Return internal temperature value in degrees celsius.""" 58 | v = self._read32() 59 | # Ignore bottom 4 bits of thermocouple data. 60 | v >>= 4 61 | # Grab bottom 11 bits as internal temperature data. 62 | internal = v & 0x7FF 63 | if v & 0x800: 64 | # Negative value, take 2's compliment. Compute this with subtraction 65 | # because python is a little odd about handling signed/unsigned. 66 | internal -= 4096 67 | # Scale by 0.0625 degrees C per bit and return value. 68 | return internal * 0.0625 69 | 70 | def readTempC(self): 71 | """Return the thermocouple temperature value in degrees celsius.""" 72 | v = self._read32() 73 | # Check for error reading value. 74 | if v & 0x7: 75 | return float('NaN') 76 | # Check if signed bit is set. 77 | if v & 0x80000000: 78 | # Negative value, take 2's compliment. Compute this with subtraction 79 | # because python is a little odd about handling signed/unsigned. 80 | v >>= 18 81 | v -= 16384 82 | else: 83 | # Positive value, just shift the bits to get the value. 84 | v >>= 18 85 | # Scale by 0.25 degrees C per bit and return value. 86 | return v * 0.25 87 | 88 | def readState(self): 89 | """Return dictionary containing fault codes and hardware problems 90 | """ 91 | v = self._read32() 92 | return { 93 | 'openCircuit': (v & (1 << 0)) > 0, 94 | 'shortGND': (v & (1 << 1)) > 0, 95 | 'shortVCC': (v & (1 << 2)) > 0, 96 | 'fault': (v & (1 << 16)) > 0 97 | } 98 | 99 | def readLinearizedTempC(self): 100 | """Return the NIST-linearized thermocouple temperature value in degrees celsius. 101 | See https://learn.adafruit.com/calibrating-sensors/maxim-31855-linearization for more info. 102 | """ 103 | # MAX31855 thermocouple voltage reading in mV 104 | thermocoupleVoltage = (self.readTempC() - self.readInternalC()) * 0.041276 105 | # MAX31855 cold junction voltage reading in mV 106 | coldJunctionTemperature = self.readInternalC() 107 | coldJunctionVoltage = (-0.176004136860E-01 + 108 | 0.389212049750E-01 * coldJunctionTemperature + 109 | 0.185587700320E-04 * math.pow(coldJunctionTemperature, 2.0) + 110 | -0.994575928740E-07 * math.pow(coldJunctionTemperature, 3.0) + 111 | 0.318409457190E-09 * math.pow(coldJunctionTemperature, 4.0) + 112 | -0.560728448890E-12 * math.pow(coldJunctionTemperature, 5.0) + 113 | 0.560750590590E-15 * math.pow(coldJunctionTemperature, 6.0) + 114 | -0.320207200030E-18 * math.pow(coldJunctionTemperature, 7.0) + 115 | 0.971511471520E-22 * math.pow(coldJunctionTemperature, 8.0) + 116 | -0.121047212750E-25 * math.pow(coldJunctionTemperature, 9.0) + 117 | 0.118597600000E+00 * math.exp(-0.118343200000E-03 * math.pow((coldJunctionTemperature-0.126968600000E+03), 2.0))) 118 | # cold junction voltage + thermocouple voltage 119 | voltageSum = thermocoupleVoltage + coldJunctionVoltage 120 | # calculate corrected temperature reading based on coefficients for 3 different ranges 121 | # float b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10; 122 | if thermocoupleVoltage < 0: 123 | b0 = 0.0000000E+00 124 | b1 = 2.5173462E+01 125 | b2 = -1.1662878E+00 126 | b3 = -1.0833638E+00 127 | b4 = -8.9773540E-01 128 | b5 = -3.7342377E-01 129 | b6 = -8.6632643E-02 130 | b7 = -1.0450598E-02 131 | b8 = -5.1920577E-04 132 | b9 = 0.0000000E+00 133 | elif thermocoupleVoltage < 20.644: 134 | b0 = 0.000000E+00 135 | b1 = 2.508355E+01 136 | b2 = 7.860106E-02 137 | b3 = -2.503131E-01 138 | b4 = 8.315270E-02 139 | b5 = -1.228034E-02 140 | b6 = 9.804036E-04 141 | b7 = -4.413030E-05 142 | b8 = 1.057734E-06 143 | b9 = -1.052755E-08 144 | elif thermocoupleVoltage < 54.886: 145 | b0 = -1.318058E+02 146 | b1 = 4.830222E+01 147 | b2 = -1.646031E+00 148 | b3 = 5.464731E-02 149 | b4 = -9.650715E-04 150 | b5 = 8.802193E-06 151 | b6 = -3.110810E-08 152 | b7 = 0.000000E+00 153 | b8 = 0.000000E+00 154 | b9 = 0.000000E+00 155 | else: 156 | # TODO: handle error - out of range 157 | return 0 158 | return (b0 + 159 | b1 * voltageSum + 160 | b2 * pow(voltageSum, 2.0) + 161 | b3 * pow(voltageSum, 3.0) + 162 | b4 * pow(voltageSum, 4.0) + 163 | b5 * pow(voltageSum, 5.0) + 164 | b6 * pow(voltageSum, 6.0) + 165 | b7 * pow(voltageSum, 7.0) + 166 | b8 * pow(voltageSum, 8.0) + 167 | b9 * pow(voltageSum, 9.0)) 168 | 169 | def _read32(self): 170 | # Read 32 bits from the SPI bus. 171 | raw = self._spi.read(4) 172 | if raw is None or len(raw) != 4: 173 | raise RuntimeError('Did not read expected number of bytes from device!') 174 | value = raw[0] << 24 | raw[1] << 16 | raw[2] << 8 | raw[3] 175 | self._logger.debug('Raw value: 0x{0:08X}'.format(value & 0xFFFFFFFF)) 176 | return value 177 | -------------------------------------------------------------------------------- /Adafruit_MAX31855/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_Python_MAX31855/f6d6bfa3e27c16fd3edabf126ad8676b3b72bed9/Adafruit_MAX31855/__init__.py -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Adafruit Industries 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DEPRECATED LIBRARY Adafruit Python MAX31855 2 | ====================================== 3 | 4 | This library has been deprecated! We are leaving this up for historical and research purposes but archiving the repository. 5 | 6 | We are now only supporting the use of our CircuitPython libraries for use with Python. 7 | 8 | Check out this guide for info on using this sensor with the CircuitPython library: https://learn.adafruit.com/thermocouple/python-circuitpython 9 | 10 | Adafruit Python MAX31855 11 | ------------------------ 12 | 13 | Python library for accessing the MAX31855 thermocouple temperature sensor on a Raspberry Pi or Beaglebone Black. 14 | 15 | Designed specifically to work with the Adafruit MAX31855 sensor ----> https://www.adafruit.com/products/269 16 | 17 | To install, first make sure some dependencies are available by running the following commands (on a Raspbian 18 | or Beaglebone Black Debian install): 19 | 20 | ```` 21 | sudo apt-get update 22 | sudo apt-get install build-essential python-dev python-smbus 23 | ```` 24 | 25 | Then download the library by clicking the download zip link to the right and unzip the archive somewhere on your Raspberry Pi or Beaglebone Black. Then execute the following command in the directory of the library: 26 | 27 | ```` 28 | sudo python setup.py install 29 | ```` 30 | 31 | Make sure you have internet access on the device so it can download the required dependencies. 32 | 33 | See examples of usage in the examples folder. 34 | 35 | Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! 36 | 37 | Written by Tony DiCola for Adafruit Industries. 38 | MIT license, all text above must be included in any redistribution 39 | -------------------------------------------------------------------------------- /examples/simpletest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Copyright (c) 2014 Adafruit Industries 3 | # Author: Tony DiCola 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 13 | # all 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 21 | # THE SOFTWARE. 22 | 23 | # Can enable debug output by uncommenting: 24 | #import logging 25 | #logging.basicConfig(level=logging.DEBUG) 26 | 27 | import time 28 | 29 | import Adafruit_GPIO.SPI as SPI 30 | import Adafruit_MAX31855.MAX31855 as MAX31855 31 | 32 | 33 | # Define a function to convert celsius to fahrenheit. 34 | def c_to_f(c): 35 | return c * 9.0 / 5.0 + 32.0 36 | 37 | 38 | # Uncomment one of the blocks of code below to configure your Pi or BBB to use 39 | # software or hardware SPI. 40 | 41 | # Raspberry Pi software SPI configuration. 42 | CLK = 25 43 | CS = 24 44 | DO = 18 45 | sensor = MAX31855.MAX31855(CLK, CS, DO) 46 | 47 | # Raspberry Pi hardware SPI configuration. 48 | #SPI_PORT = 0 49 | #SPI_DEVICE = 0 50 | #sensor = MAX31855.MAX31855(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE)) 51 | 52 | # BeagleBone Black software SPI configuration. 53 | #CLK = 'P9_12' 54 | #CS = 'P9_15' 55 | #DO = 'P9_23' 56 | #sensor = MAX31855.MAX31855(CLK, CS, DO) 57 | 58 | # BeagleBone Black hardware SPI configuration. 59 | #SPI_PORT = 1 60 | #SPI_DEVICE = 0 61 | #sensor = MAX31855.MAX31855(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE)) 62 | 63 | # Loop printing measurements every second. 64 | print('Press Ctrl-C to quit.') 65 | while True: 66 | temp = sensor.readTempC() 67 | internal = sensor.readInternalC() 68 | print('Thermocouple Temperature: {0:0.3F}*C / {1:0.3F}*F'.format(temp, c_to_f(temp))) 69 | print(' Internal Temperature: {0:0.3F}*C / {1:0.3F}*F'.format(internal, c_to_f(internal))) 70 | time.sleep(1.0) 71 | -------------------------------------------------------------------------------- /ez_setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Bootstrap setuptools installation 3 | 4 | To use setuptools in your package's setup.py, include this 5 | file in the same directory and add this to the top of your setup.py:: 6 | 7 | from ez_setup import use_setuptools 8 | use_setuptools() 9 | 10 | To require a specific version of setuptools, set a download 11 | mirror, or use an alternate download directory, simply supply 12 | the appropriate options to ``use_setuptools()``. 13 | 14 | This file can also be run as a script to install or upgrade setuptools. 15 | """ 16 | import os 17 | import shutil 18 | import sys 19 | import tempfile 20 | import zipfile 21 | import optparse 22 | import subprocess 23 | import platform 24 | import textwrap 25 | import contextlib 26 | 27 | from distutils import log 28 | 29 | try: 30 | from site import USER_SITE 31 | except ImportError: 32 | USER_SITE = None 33 | 34 | DEFAULT_VERSION = "3.5.1" 35 | DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/" 36 | 37 | def _python_cmd(*args): 38 | """ 39 | Return True if the command succeeded. 40 | """ 41 | args = (sys.executable,) + args 42 | return subprocess.call(args) == 0 43 | 44 | 45 | def _install(archive_filename, install_args=()): 46 | with archive_context(archive_filename): 47 | # installing 48 | log.warn('Installing Setuptools') 49 | if not _python_cmd('setup.py', 'install', *install_args): 50 | log.warn('Something went wrong during the installation.') 51 | log.warn('See the error message above.') 52 | # exitcode will be 2 53 | return 2 54 | 55 | 56 | def _build_egg(egg, archive_filename, to_dir): 57 | with archive_context(archive_filename): 58 | # building an egg 59 | log.warn('Building a Setuptools egg in %s', to_dir) 60 | _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) 61 | # returning the result 62 | log.warn(egg) 63 | if not os.path.exists(egg): 64 | raise IOError('Could not build the egg.') 65 | 66 | 67 | def get_zip_class(): 68 | """ 69 | Supplement ZipFile class to support context manager for Python 2.6 70 | """ 71 | class ContextualZipFile(zipfile.ZipFile): 72 | def __enter__(self): 73 | return self 74 | def __exit__(self, type, value, traceback): 75 | self.close 76 | return zipfile.ZipFile if hasattr(zipfile.ZipFile, '__exit__') else \ 77 | ContextualZipFile 78 | 79 | 80 | @contextlib.contextmanager 81 | def archive_context(filename): 82 | # extracting the archive 83 | tmpdir = tempfile.mkdtemp() 84 | log.warn('Extracting in %s', tmpdir) 85 | old_wd = os.getcwd() 86 | try: 87 | os.chdir(tmpdir) 88 | with get_zip_class()(filename) as archive: 89 | archive.extractall() 90 | 91 | # going in the directory 92 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) 93 | os.chdir(subdir) 94 | log.warn('Now working in %s', subdir) 95 | yield 96 | 97 | finally: 98 | os.chdir(old_wd) 99 | shutil.rmtree(tmpdir) 100 | 101 | 102 | def _do_download(version, download_base, to_dir, download_delay): 103 | egg = os.path.join(to_dir, 'setuptools-%s-py%d.%d.egg' 104 | % (version, sys.version_info[0], sys.version_info[1])) 105 | if not os.path.exists(egg): 106 | archive = download_setuptools(version, download_base, 107 | to_dir, download_delay) 108 | _build_egg(egg, archive, to_dir) 109 | sys.path.insert(0, egg) 110 | 111 | # Remove previously-imported pkg_resources if present (see 112 | # https://bitbucket.org/pypa/setuptools/pull-request/7/ for details). 113 | if 'pkg_resources' in sys.modules: 114 | del sys.modules['pkg_resources'] 115 | 116 | import setuptools 117 | setuptools.bootstrap_install_from = egg 118 | 119 | 120 | def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 121 | to_dir=os.curdir, download_delay=15): 122 | to_dir = os.path.abspath(to_dir) 123 | rep_modules = 'pkg_resources', 'setuptools' 124 | imported = set(sys.modules).intersection(rep_modules) 125 | try: 126 | import pkg_resources 127 | except ImportError: 128 | return _do_download(version, download_base, to_dir, download_delay) 129 | try: 130 | pkg_resources.require("setuptools>=" + version) 131 | return 132 | except pkg_resources.DistributionNotFound: 133 | return _do_download(version, download_base, to_dir, download_delay) 134 | except pkg_resources.VersionConflict as VC_err: 135 | if imported: 136 | msg = textwrap.dedent(""" 137 | The required version of setuptools (>={version}) is not available, 138 | and can't be installed while this script is running. Please 139 | install a more recent version first, using 140 | 'easy_install -U setuptools'. 141 | 142 | (Currently using {VC_err.args[0]!r}) 143 | """).format(VC_err=VC_err, version=version) 144 | sys.stderr.write(msg) 145 | sys.exit(2) 146 | 147 | # otherwise, reload ok 148 | del pkg_resources, sys.modules['pkg_resources'] 149 | return _do_download(version, download_base, to_dir, download_delay) 150 | 151 | def _clean_check(cmd, target): 152 | """ 153 | Run the command to download target. If the command fails, clean up before 154 | re-raising the error. 155 | """ 156 | try: 157 | subprocess.check_call(cmd) 158 | except subprocess.CalledProcessError: 159 | if os.access(target, os.F_OK): 160 | os.unlink(target) 161 | raise 162 | 163 | def download_file_powershell(url, target): 164 | """ 165 | Download the file at url to target using Powershell (which will validate 166 | trust). Raise an exception if the command cannot complete. 167 | """ 168 | target = os.path.abspath(target) 169 | cmd = [ 170 | 'powershell', 171 | '-Command', 172 | "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)" % vars(), 173 | ] 174 | _clean_check(cmd, target) 175 | 176 | def has_powershell(): 177 | if platform.system() != 'Windows': 178 | return False 179 | cmd = ['powershell', '-Command', 'echo test'] 180 | devnull = open(os.path.devnull, 'wb') 181 | try: 182 | try: 183 | subprocess.check_call(cmd, stdout=devnull, stderr=devnull) 184 | except Exception: 185 | return False 186 | finally: 187 | devnull.close() 188 | return True 189 | 190 | download_file_powershell.viable = has_powershell 191 | 192 | def download_file_curl(url, target): 193 | cmd = ['curl', url, '--silent', '--output', target] 194 | _clean_check(cmd, target) 195 | 196 | def has_curl(): 197 | cmd = ['curl', '--version'] 198 | devnull = open(os.path.devnull, 'wb') 199 | try: 200 | try: 201 | subprocess.check_call(cmd, stdout=devnull, stderr=devnull) 202 | except Exception: 203 | return False 204 | finally: 205 | devnull.close() 206 | return True 207 | 208 | download_file_curl.viable = has_curl 209 | 210 | def download_file_wget(url, target): 211 | cmd = ['wget', url, '--quiet', '--output-document', target] 212 | _clean_check(cmd, target) 213 | 214 | def has_wget(): 215 | cmd = ['wget', '--version'] 216 | devnull = open(os.path.devnull, 'wb') 217 | try: 218 | try: 219 | subprocess.check_call(cmd, stdout=devnull, stderr=devnull) 220 | except Exception: 221 | return False 222 | finally: 223 | devnull.close() 224 | return True 225 | 226 | download_file_wget.viable = has_wget 227 | 228 | def download_file_insecure(url, target): 229 | """ 230 | Use Python to download the file, even though it cannot authenticate the 231 | connection. 232 | """ 233 | try: 234 | from urllib.request import urlopen 235 | except ImportError: 236 | from urllib2 import urlopen 237 | src = dst = None 238 | try: 239 | src = urlopen(url) 240 | # Read/write all in one block, so we don't create a corrupt file 241 | # if the download is interrupted. 242 | data = src.read() 243 | dst = open(target, "wb") 244 | dst.write(data) 245 | finally: 246 | if src: 247 | src.close() 248 | if dst: 249 | dst.close() 250 | 251 | download_file_insecure.viable = lambda: True 252 | 253 | def get_best_downloader(): 254 | downloaders = [ 255 | download_file_powershell, 256 | download_file_curl, 257 | download_file_wget, 258 | download_file_insecure, 259 | ] 260 | 261 | for dl in downloaders: 262 | if dl.viable(): 263 | return dl 264 | 265 | def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 266 | to_dir=os.curdir, delay=15, downloader_factory=get_best_downloader): 267 | """ 268 | Download setuptools from a specified location and return its filename 269 | 270 | `version` should be a valid setuptools version number that is available 271 | as an egg for download under the `download_base` URL (which should end 272 | with a '/'). `to_dir` is the directory where the egg will be downloaded. 273 | `delay` is the number of seconds to pause before an actual download 274 | attempt. 275 | 276 | ``downloader_factory`` should be a function taking no arguments and 277 | returning a function for downloading a URL to a target. 278 | """ 279 | # making sure we use the absolute path 280 | to_dir = os.path.abspath(to_dir) 281 | zip_name = "setuptools-%s.zip" % version 282 | url = download_base + zip_name 283 | saveto = os.path.join(to_dir, zip_name) 284 | if not os.path.exists(saveto): # Avoid repeated downloads 285 | log.warn("Downloading %s", url) 286 | downloader = downloader_factory() 287 | downloader(url, saveto) 288 | return os.path.realpath(saveto) 289 | 290 | def _build_install_args(options): 291 | """ 292 | Build the arguments to 'python setup.py install' on the setuptools package 293 | """ 294 | return ['--user'] if options.user_install else [] 295 | 296 | def _parse_args(): 297 | """ 298 | Parse the command line for options 299 | """ 300 | parser = optparse.OptionParser() 301 | parser.add_option( 302 | '--user', dest='user_install', action='store_true', default=False, 303 | help='install in user site package (requires Python 2.6 or later)') 304 | parser.add_option( 305 | '--download-base', dest='download_base', metavar="URL", 306 | default=DEFAULT_URL, 307 | help='alternative URL from where to download the setuptools package') 308 | parser.add_option( 309 | '--insecure', dest='downloader_factory', action='store_const', 310 | const=lambda: download_file_insecure, default=get_best_downloader, 311 | help='Use internal, non-validating downloader' 312 | ) 313 | parser.add_option( 314 | '--version', help="Specify which version to download", 315 | default=DEFAULT_VERSION, 316 | ) 317 | options, args = parser.parse_args() 318 | # positional arguments are ignored 319 | return options 320 | 321 | def main(): 322 | """Install or upgrade setuptools and EasyInstall""" 323 | options = _parse_args() 324 | archive = download_setuptools( 325 | version=options.version, 326 | download_base=options.download_base, 327 | downloader_factory=options.downloader_factory, 328 | ) 329 | return _install(archive, _build_install_args(options)) 330 | 331 | if __name__ == '__main__': 332 | sys.exit(main()) 333 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | try: 2 | # Try using ez_setup to install setuptools if not already installed. 3 | from ez_setup import use_setuptools 4 | use_setuptools() 5 | except ImportError: 6 | # Ignore import error and assume Python 3 which already has setuptools. 7 | pass 8 | 9 | from setuptools import setup, find_packages 10 | 11 | setup(name = 'Adafruit_MAX31855', 12 | version = '1.6.1', 13 | author = 'Tony DiCola', 14 | author_email = 'tdicola@adafruit.com', 15 | description = 'Library for accessing the MAX31855 thermocouple temperature sensor on a Raspberry Pi or Beaglebone Black.', 16 | license = 'MIT', 17 | url = 'https://github.com/adafruit/Adafruit_Python_MAX31855/', 18 | dependency_links = ['https://github.com/adafruit/Adafruit_Python_GPIO/tarball/master#egg=Adafruit-GPIO-0.6.5'], 19 | install_requires = ['Adafruit-GPIO>=0.6.5'], 20 | packages = find_packages()) 21 | --------------------------------------------------------------------------------