diff --git a/.gitignore b/.gitignore index 8ce7ab9..edeb66a 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,4 @@ docs/_build/ target/ .idea/ +pitmaster/csv/ diff --git a/pitmaster/executable.py b/pitmaster/executable.py index 2c36aac..ccc7448 100644 --- a/pitmaster/executable.py +++ b/pitmaster/executable.py @@ -55,6 +55,20 @@ def _setup_arg_parser(): action='store_true', help="Enable the LCD display or not. It is disabled by default." ) + parser.add_argument( + "-l", + "--localdisplay", + action='store_true', + help="Enable console output or not. It is disabled by default." + ) + parser.add_argument( + "-p", + "--probetype", + required=True, + action='store', + help="Configure which type of probes to use." + "This is either thermistor or thermocouple" + ) return parser @@ -69,7 +83,9 @@ def execute(): cook_name = provided_args.cookname output_file = provided_args.output use_lcd = provided_args.tft - sensors = sensor.find_temp_sensors() + probe_type = provided_args.probetype + local_display = provided_args.localdisplay + sensors = sensor.find_temp_sensors(probe_type) data_obj = DBObject(filename=output_file) if use_lcd: display = LocalDisplay() @@ -77,7 +93,7 @@ def execute(): try: while True: for sen in sensors: - temp_c = sensor.read_temp(sen["location"]) + temp_c = sensor.read_temp(sen["location"], probe_type=probe_type) temp_f = temps.from_c_to_f(temp=temp_c) info = { "date": time.time(), @@ -87,6 +103,8 @@ def execute(): "cook_name": cook_name } data_obj.save(info=info) + if local_display: + print info if use_lcd: display.check_events() display.set_display_msg("{}: {}f".format( diff --git a/pitmaster/tools/sensor.py b/pitmaster/tools/sensor.py index 5bc74c2..5da8f0d 100644 --- a/pitmaster/tools/sensor.py +++ b/pitmaster/tools/sensor.py @@ -13,9 +13,24 @@ # limitations under the License. import os import time +import math +import RPi.GPIO as GPIO from pitmaster.exceptions import * +SPICLK = 18 +SPIMOSI = 24 +SPIMISO = 23 +SPICS = 25 + +GPIO.setmode(GPIO.BCM) +DEBUG = 1 +# set up the SPI interface pins +GPIO.setup(SPIMOSI, GPIO.OUT) +GPIO.setup(SPIMISO, GPIO.IN) +GPIO.setup(SPICLK, GPIO.OUT) +GPIO.setup(SPICS, GPIO.OUT) + def _temp_raw(sensor=None): with open(sensor, "r") as file_reader: @@ -23,7 +38,67 @@ def _temp_raw(sensor=None): return lines -def read_temp(sensor=None, offset=None): +def _read_thermistor(sensor=None): + adcnum = int(sensor) + clockpin = SPICLK + mosipin = SPIMOSI + misopin = SPIMISO + cspin = SPICS + + if ((adcnum > 7) or (adcnum < 0)): + raise SensorNotFoundException("Invalid Thermisor Location: {}".format(sensor)) + + GPIO.output(cspin, True) + GPIO.output(clockpin, False) # start clock low + GPIO.output(cspin, False) # bring CS low + + commandout = adcnum + commandout |= 0x18 # start bit + single-ended bit + commandout <<= 3 # we only need to send 5 bits here + + for i in range(5): + if (commandout & 0x80): + GPIO.output(mosipin, True) + else: + GPIO.output(mosipin, False) + commandout <<= 1 + GPIO.output(clockpin, True) + GPIO.output(clockpin, False) + + adcout = 0 + # read in one empty bit, one null bit and 10 ADC bits + for i in range(12): + GPIO.output(clockpin, True) + GPIO.output(clockpin, False) + adcout <<= 1 + if (GPIO.input(misopin)): + adcout |= 0x1 + + GPIO.output(cspin, True) + + adcout >>= 1 # first bit is 'null' so drop it + resistor_size = 10000 + r1 = (1023.0 / adcout) - 1.0 + if r1 > 0: + resistance = resistor_size / r1 + else: + return -1 + + sth_coef_a = 0.000436925136556 + sth_coef_b = 0.000230203788274 + sth_coef_c = 0.000000060486575 + + if resistance is None: + raise MissingPropertyException("resistance can not be None!") + t = sth_coef_a + t += sth_coef_b * (math.log(resistance)) + t += sth_coef_c * math.pow((math.log(resistance)), 3) + t = 1 / t + t -= 273.15 + return t + + +def read_temp(sensor=None, offset=None, probe_type=None): """ Reads the temp sensor and returns its temp in C. @@ -33,34 +108,60 @@ def read_temp(sensor=None, offset=None): """ if sensor is None: raise MissingPropertyException("sensor must not be None!") + if probe_type is None: + raise MissingPropertyException("must specify probe type!") if offset is None: offset = 0 - if not os.path.isfile(sensor): - raise SensorNotFoundException("Unable to locate: {}".format(sensor)) - lines = _temp_raw(sensor) - while lines[0].strip()[-3] != 'Y': - time.sleep(0.2) - lines = _temp_raw() - temp_output = lines[1].find('t=') - if temp_output != -1: - temp_string = lines[1].strip()[temp_output + 2:] - temp_c = (float(temp_string) / 1000.0) + offset + if probe_type != "thermistor": + if not os.path.isfile(sensor): + raise SensorNotFoundException("Unable to locate: {}".format(sensor)) + lines = _temp_raw(sensor) + while lines[0].strip()[-3] != 'Y': + time.sleep(0.2) + lines = _temp_raw() + temp_output = lines[1].find('t=') + if temp_output != -1: + temp_string = lines[1].strip()[temp_output + 2:] + temp_c = (float(temp_string) / 1000.0) + offset + return temp_c + else: + temp_c = _read_thermistor(sensor) + offset return temp_c -def find_temp_sensors(): +def find_temp_sensors(probe_type=None): """ Looks on system for temp sensors and returns all that it finds in a list :return list: List containing all sensors. """ - # Hard coded for now while we work out the best way to handel this. - return [ - { - "name": "Probe 1", - "location": "/sys/bus/w1/devices/3b-0000001921e8/w1_slave" - } - ] + if probe_type is None: + raise MissingPropertyException("probe type must be set!") + + if probe_type == "thermistor": + return [ + { + "name": "Probe 1", + "location": "0" + }, + { + "name": "Probe 2", + "location": "1" + }, + { + "name": "Probe 3", + "location": "2" + } + ] + else: + # Hard coded for now while we work out the best way to handel this. + return [ + { + "name": "Probe 1", + "location": "/sys/bus/w1/devices/3b-0000001921e8/w1_slave" + } + ] + if __name__ == "__main__": for i in range(15): diff --git a/pitmaster/tools/temps.py b/pitmaster/tools/temps.py index 33a9a66..ec28cce 100644 --- a/pitmaster/tools/temps.py +++ b/pitmaster/tools/temps.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from numbers import Number +import math from pitmaster.exceptions import * @@ -29,4 +30,4 @@ def from_c_to_f(temp=None): raise InvalidPropertyException( "temp must be a valid number. Found: {}".format(type(temp)) ) - return (temp * 9/5) + 32.0 + return (temp * 9 / 5) + 32.0