Example #1
0
    def _update(self):
        updateTime = self.lastUpdateTime + datetime.timedelta(
            seconds=self.interval)

        # check update flag is enabled
        # check Brewfather URL is defined
        # check the updated interval has elapsed since last update
        # check relevant data for the system is valid
        # check the data has been updated since last update
        if self.bUpdate and self.sURL != "" and datetime.datetime.now() > updateTime and \
            self.postdata["name"] != "" and \
            self.bNewData:

            try:
                self.jsondump = json.dumps(self.postdata).encode('utf8')
                req = request.Request(
                    self.sURL,
                    data=self.jsondump,
                    headers={'content-type': 'application/json'})
                response = request.urlopen(req)
                self.bNewData = False
                self.lastUpdateTime = datetime.datetime.now()
                logger.info("BrewFather: " + self.postdata["temp"] + "C, " +
                            self.postdata["gravity"] + "SG, " +
                            self.postdata["aux_temp"] + "C, " +
                            self.lastUpdateTime.strftime("%d.%m.%Y %H:%M:%S"))
            except:
                logger.error("Exception posting to Brewfather: " +
                             self.getLastJSON())
        else:
            logger.debug("Update parameters:\nbUpdate = "+str(self.bUpdate)+"\nsUrl = "+self.sURL+"\npostdata.Name = "+self.postdata["name"] + \
                "\npostdata.temp = "+self.postdata["temp"]+"\npostdata.gravity = "+self.postdata["gravity"] + "\npostdata.aux_temp = "+self.postdata["aux_temp"] + \
                        "\nupdateTime = "+updateTime.strftime("%d.%m.%Y %H:%M:%S") + \
                            "\nlastUpdateTime = "+self.lastUpdateTime.strftime("%d.%m.%Y %H:%M:%S") + \
                               "\nCurrent Time = "+datetime.datetime.now().strftime("%d.%m.%Y %H:%M:%S"))
Example #2
0
    def run(self):

        logger.info("Starting Controller")
        self.bStopThread = False
        
        while self.bStopThread != True:
            curTime = datetime.datetime.now()
            sTime = curTime.strftime("%d.%m.%Y %H:%M:%S")

            self._readConf()
             # request status from Arduino
            self._updateState()

            time.sleep(UPDATE_INVERVAL)

            # reads and processes all data from serial queue
            while self.ser.inWaiting() > 0:
                inputValue = self.ser.readline()
                str = inputValue.decode()
                str = str.strip()
                logger.debug("RESPONSE Raw: "+str)
                self._processControllerResponse(str)

            if self.bStopRequest:
                if not self.bCoolOn and not self.bHeatOn:
                    self.bStopThread = True
                else:
                    self.stopHeatingCooling()   


        logger.info("Controller Stopped")
Example #3
0
    def _sender_receiver(self):
        """Receive packet and send its own packet through rfm95."""
        while True:
            # if there is something to send, send it.
            if self.packets_to_send:
                packet_to_send = self.packets_to_send.pop()
                self._send_packet(packet_to_send)

            # if there is no packet to send
            else:
                received_packet = self._receive()

                # if nothing is received, continue
                if not received_packet:
                    continue

                # if the package has already been received, continue
                if self._packet_already_received(received_packet):
                    id_to, id_from, id_packet, flags = received_packet[:4]
                    logger.debug(
                        'message (id : {}) already received : ignoring'.format(id_packet))
                    continue

                # else, keep a trace of the packet
                self._remember_we_got_that_packet(received_packet)

                # if the packet is for me, drop it in the inbox
                if self._is_packet_for_me(received_packet):
                    self.drop_in_inbox(received_packet)

                # if the packet is not for me, or if it is
                # for everyone, forward it.
                if not(self._is_packet_for_me(received_packet)) \
                        or self._is_packet_for_everyone(received_packet):
                    self.packets_to_send.append(received_packet)
    def read_data_from_futek_or_velostat(self, folder_name, pure_file_name):
        starting_exp_timestamp = 0.0
        starting_exp_timestamp_file_path = "/home/app/tactile_sensor_velostat/experimental_data/starting_exp_time/starting_experiment_" + pure_file_name + ".txt"
        if isfile(starting_exp_timestamp_file_path):
            tex_file = open(starting_exp_timestamp_file_path, mode="r")
            starting_exp_timestamp = float(tex_file.readline())

        logger.debug("I took %s folder with %s name", folder_name,
                     pure_file_name)
        t = []
        data = []
        text = []
        temp = "/home/app/tactile_sensor_velostat/experimental_data/" + folder_name
        file_name = temp + "/exp_" + pure_file_name + ".txt"
        print("name is " + file_name)
        text_file = open(file_name, "r")

        for line in text_file:
            full_line_data = line.split(" ")
            if float(full_line_data[1]) < starting_exp_timestamp:
                continue
            data.append(float(full_line_data[0]))
            t.append(float(full_line_data[1]))
            if len(full_line_data) > 2:
                text.append(full_line_data[2])
            else:
                text.append("")
        return t, data, text
Example #5
0
    def _readConf(self):

        try:
            if os.path.isfile(CONFIGFILE) == False:
                logger.error("Controller configuration file is not valid: "+CONFIGFILE)

            ini = configparser.ConfigParser()
            ini.read(CONFIGFILE)

            if 'Controller' in ini:
                logger.debug("Reading Controller config")
        
                config = ini['Controller']
                
                try:
                    if config["MessageLevel"] == "DEBUG":
                        logger.setLevel(logging.DEBUG)
                    elif config["MessageLevel"] == "WARNING":
                        logger.setLevel(logging.WARNING)
                    elif config["MessageLevel"] == "ERROR":
                        logger.setLevel(logging.ERROR)
                    elif config["MessageLevel"] == "INFO":
                        logger.setLevel(logging.INFO)
                    else:
                        logger.setLevel(logging.INFO)
                except KeyError:
                    logger.setLevel(logging.INFO)
                
                try:
                    if config["BeerTempAdjust"] != "":
                        self.beerTAdjust = float(config.get("BeerTempAdjust"))
                    else:
                        raise Exception
                except:
                    self.beerTAdjust = 0.0
                    logger.warning("Invalid BeerTempAdjust in configuration; using default: "+str(self.beerTAdjust))

                try:
                    if config["ChamberTempAdjust"] != "":
                        self.chamberTAdjust = float(config.get("ChamberTempAdjust"))
                    else:
                        raise Exception
                except:
                    self.chamberTAdjust = 0.0
                    logger.warning("Invalid BeerTempAdjust in configuration; using default: "+str(self.chamberTAdjust))

                try:
                    if config["OnDelay"] != "" and int(config["OnDelay"]) >= 0:
                        self.onDelay = int(config.get("OnDelay"))*60
                    else:
                        raise Exception
                except:
                    self.onDelay = DEFAULT_ON_DELAY
                    logger.warning("Invalid OnDelay in configuration; using default: "+str(self.onDelay)+" seconds")

        except:
            logger.warning("Problem read from configuration file: "+CONFIGFILE)
       
        logger.debug("Controller config updated")
 def read_all_data_for_drawing_froce_comp(self, name, folder_subname=""):
     if folder_subname != "":
         folder_subname = "/" + folder_subname
     t_vel, data_vel, text_vel = self.read_data_from_futek_or_velostat(
         "velostat_data" + folder_subname, name)
     t_futek, data_futek, text_futek = self.read_data_from_futek_or_velostat(
         "futek_data" + folder_subname, name)
     logger.debug(len(t_vel))
     return [[t_vel, t_futek], [data_vel, data_futek],
             [text_vel, text_futek]]
Example #7
0
 def _update(self):
     updateTime = self.lastUpdateTime + timedelta(seconds=self.interval)
     if datetime.now() > updateTime:
         logger.debug("Update data")
         self._readdata()
         self.lastUpdateTime = datetime.now()
     else:
         logger.debug("Update interval not reached:" +
                      datetime.now().strftime(DATETIME_FORMAT) + " / " +
                      updateTime.strftime(DATETIME_FORMAT))
Example #8
0
    def __init__(self, _sWelcome):
        threading.Thread.__init__(self)

        # variables to hold pir current and last states
        self.pir_state = 0
        self.bStopRequest = False

        self.iDisplay = 1

        self.sScreen1Row1 = _sWelcome
        self.sScreen1Row2 = " Target:        "
        self.sScreen2Row1 = "     SG:        "
        self.sScreen2Row2 = "   Beer:        "
        self.sScreen3Row1 = "(W)Beer:        "
        self.sScreen3Row2 = "Chamber:        "
        self.lcdOffTime = datetime.datetime.now()
        self.displaySwitchTime = datetime.datetime.now() + datetime.timedelta(
            seconds=DISPLAY_ON_SEC)
        self.dataTime = datetime.datetime.now()

        # Initialize the GPIO Pins
        os.system('modprobe w1-gpio')  # Turns on the GPIO module

        # Set the GPIO naming conventions
        GPIO.setmode(GPIO.BCM)
        GPIO.setwarnings(False)

        # Set the three GPIO pins for Output
        GPIO.setup(PIN_PIR, GPIO.IN)

        # Create LCD, passing in MCP GPIO adapter.
        self.lcd = I2C_LCD_driver.lcd()
        time.sleep(5)
        self.lcd.backlight(0)
        self.bLcdOn = False

        if _sWelcome != None:
            self.lcd.backlight(1)
            self.bLcdOn = True
            self.lcd.lcd_display_string(_sWelcome, 1)
            self.lcdOffTime = datetime.datetime.now() + datetime.timedelta(
                seconds=LCD_ON_SEC)
            logger.debug("1 - LCD is on to show welcome")

        else:
            self.lcd.backlight(0)
            self.bLcdOn = False

        # Loop until PIR output is 0
        while GPIO.input(PIN_PIR) == 1:
            self.pir_state = 0
Example #9
0
def get_reference_length_and_width(centroids):
    # Order coordinates in clockwise order
    tl, tr, br, bl = order_points(centroids)
    # The 'four_point_transform' function from imutils assumes that the width
    # and length of the new image will be the maximum respective width and 
    # lengths of the given quadrilateral polygon. Hence, I do the same here.
    bottom_width = int(euclidean(br, bl))
    top_width = int(euclidean(tr, tl))
    left_height = int(euclidean(bl, tl))
    right_height = int(euclidean(br, tr))

    logger.debug(f'Bottom width [px]: {bottom_width:.1f} px')
    logger.debug(f'Top width [px]: {top_width:.1f} px')
    logger.debug(f'Left height [px]: {left_height:.1f} px')
    logger.debug(f'Right height [px]: {right_height:.1f} px')

    width_px = max(bottom_width, top_width)
    height_px = max(left_height, right_height)
    return height_px, width_px
Example #10
0
    def startHeating(self):
        curTime = datetime.datetime.now()
        sTime = curTime.strftime("%d.%m.%Y %H:%M:%S")
        
        logger.debug("("+sTime+"): Heating request")

        if curTime > self.heatEndTime + datetime.timedelta(seconds=self.onDelay):
            logger.debug("("+sTime+"): Heating Turned ON")
            self.ser.write(b'H\n')
        else:
            logger.debug("("+sTime+"): Heating delay has not expired")
            self.ser.write(b'O\n')
Example #11
0
 def __del__(self):
     logger.debug("Delete chamber class")
Example #12
0
    def _readConf(self):

        try:
            if os.path.isfile(CONFIGFILE) == False:
                logger.error("Chamber configuration file is not valid: " +
                             CONFIGFILE)

            ini = configparser.ConfigParser()
            ini.read(CONFIGFILE)

            if 'Chamber' in ini:
                logger.debug("Reading Chamber config")

                config = ini['Chamber']

                try:
                    if config["MessageLevel"] == "DEBUG":
                        logger.setLevel(logging.DEBUG)
                    elif config["MessageLevel"] == "WARNING":
                        logger.setLevel(logging.WARNING)
                    elif config["MessageLevel"] == "ERROR":
                        logger.setLevel(logging.ERROR)
                    elif config["MessageLevel"] == "INFO":
                        logger.setLevel(logging.INFO)
                    else:
                        logger.setLevel(logging.INFO)
                except KeyError:
                    logger.setLevel(logging.INFO)

                # Read temperatures to target for each date
                try:
                    if config["Temps"] != "":
                        self.targetTemps = []
                        t = config["Temps"].split(",")
                        for x in t:
                            self.targetTemps.append(float(x))
                    else:
                        raise Exception
                except:
                    self.targetTemps = [DEFAULT_TEMP]
                    logger.warning("Invalid temp values; using default: " +
                                   str(self.targetTemps[0]))

                # Read dates when temperature should change
                try:
                    if config["Dates"] != "":
                        self.tempDates = []
                        dts = config["Dates"].split(",")
                        for x in dts:
                            self.tempDates.append(
                                datetime.datetime.strptime(
                                    x, '%d/%m/%Y %H:%M:%S'))
                    else:
                        raise Exception
                except:
                    self.tempDates = [
                        datetime.datetime.now(),
                        datetime.datetime.now()
                    ]
                    logger.warning(
                        "Invalid date values; using default. Heating/cooling will NOT start"
                    )

                if len(self.tempDates) != len(self.targetTemps) + 1:
                    self.tempDates = [
                        datetime.datetime.now(),
                        datetime.datetime.now()
                    ]
                    self.targetTemps = [DEFAULT_TEMP]
                    logger.warning(
                        "Invalid date or time values; using default. Heating/cooling will NOT start"
                    )

                try:
                    if config["BeerTemperatureBuffer"] != "" and float(
                            config["BeerTemperatureBuffer"]) >= 0.0:
                        self.bufferBeerTemp = float(
                            config.get("BeerTemperatureBuffer"))
                    else:
                        raise Exception
                except:
                    self.bufferBeerTemp = DEFAULT_BUFFER_BEER_TEMP
                    logger.warning(
                        "Invalid beer temperature buffer in configuration; using default: "
                        + str(self.bufferBeerTemp))

                try:
                    if config["ChamberScaleBuffer"] != "" and float(
                            config["ChamberScaleBuffer"]) >= 0.0:
                        self.bufferChamberScale = float(
                            config.get("ChamberScaleBuffer"))
                    else:
                        raise Exception
                except:
                    self.bufferChamberScale = DEFAULT_BUFFER_CHAMBER_SCALE
                    logger.warning(
                        "Invalid chamber scale buffer in configuration; using default: "
                        + str(self.bufferChamberScale))

        except:
            logger.warning("Problem read from configuration file: " +
                           CONFIGFILE)

        logger.debug("Chamber config updated")
Example #13
0
    def run(self):
        while not self.bStopRequest:
            curTime = datetime.datetime.now()

            # No data has been sent to interface in 15s so clear old data from being shown
            if curTime > self.dataTime + datetime.timedelta(seconds=15):
                self.clearScreen()
                logger.debug(
                    "No data sent to interface within 15s, clearing data shown"
                )

            # Set which of the displays should be shown
            if curTime > self.displaySwitchTime:
                self.iDisplay = self.iDisplay + 1
                if self.iDisplay > NUM_DISPLAYS:
                    self.iDisplay = 1

                self.displaySwitchTime = curTime + datetime.timedelta(
                    seconds=DISPLAY_ON_SEC)
                self.lcd.lcd_clear()

            self.pir_state = GPIO.input(PIN_PIR)

            # Motion detected
            if self.pir_state == 1:

                # Display should be turned on if not already on
                self.lcd.backlight(1)
                self.bLcdOn = True

                # Reset timeout of display when motion is detected
                self.lcdOffTime = curTime + datetime.timedelta(
                    seconds=LCD_ON_SEC)

                logger.debug(
                    "LCD ON due to detected motion, timeout reset -> PIR_STATE: "
                    + str(self.pir_state) + " bLcdOn: " + str(self.bLcdOn) +
                    " curTime: " + curTime.strftime("%d.%m.%Y %H:%M:%S") +
                    " lcdOffTime: " +
                    self.lcdOffTime.strftime("%d.%m.%Y %H:%M:%S"))

            # Motion not detected
            else:

                # display is on
                if self.bLcdOn:

                    # Display should be turned off as timeout has expired
                    if curTime > self.lcdOffTime:
                        self.lcd.lcd_clear()
                        self.lcd.backlight(0)
                        self.bLcdOn = False

                        logger.debug(
                            "Turning LCD OFF -> PIR_STATE: " +
                            str(self.pir_state) + " bLcdOn: " +
                            str(self.bLcdOn) + " curTime: " +
                            curTime.strftime("%d.%m.%Y %H:%M:%S") +
                            " lcdOffTime: " +
                            self.lcdOffTime.strftime("%d.%m.%Y %H:%M:%S"))

                    # Display on until timeout expires
                    else:
                        logger.debug(
                            "LCD ON without motion until timeout -> PIR_STATE: "
                            + str(self.pir_state) + " bLcdOn: " +
                            str(self.bLcdOn) + " curTime: " +
                            curTime.strftime("%d.%m.%Y %H:%M:%S") +
                            " lcdOffTime: " +
                            self.lcdOffTime.strftime("%d.%m.%Y %H:%M:%S"))

                # Normal state for LCD to be off when no motion detected
                else:
                    self.lcd.backlight(0)
                    self.bLcdOn = False
                    logger.debug("LCD remains OFF -> PIR_STATE: " +
                                 str(self.pir_state) + " bLcdOn: " +
                                 str(self.bLcdOn))

            try:

                # If display is ON show latest values
                if self.bLcdOn:
                    if self.iDisplay == 1:
                        logger.debug("Displaying screen 1")
                        self.lcd.lcd_display_string(self.sScreen1Row1, 1)
                        self.lcd.lcd_display_string(self.sScreen1Row2, 2)
                    elif self.iDisplay == 2:
                        logger.debug("Displaying screen 2")
                        self.lcd.lcd_display_string(self.sScreen2Row1, 1)
                        self.lcd.lcd_display_string(self.sScreen2Row2, 2)
                    elif self.iDisplay == 3:
                        logger.debug("Displaying screen 3")
                        self.lcd.lcd_display_string(self.sScreen3Row1, 1)
                        self.lcd.lcd_display_string(self.sScreen3Row2, 2)
                    else:
                        self.iDisplay = 1
                        logger.debug(
                            "Display increment messed up; resetting to 1")

            except:
                logger.error("*** PROBLEM WRITING TO LCD ***")

                # This line caused another exception in logging system
                #                logger.error("Error:", sys.exc_info()[0])

                # Recreate LCD
                self.lcd = I2C_LCD_driver.lcd()
                time.sleep(5)

                self.lcd.lcd_clear()
                self.lcdOffTime = curTime
                self.lcd.backlight(0)
                self.bLcdOn = False

                logger.debug(self.sScreen1Row1)
                logger.debug(self.sScreen1Row2)
                logger.debug(self.sScreen2Row1)
                logger.debug(self.sScreen2Row2)
                logger.debug(self.sScreen3Row1)
                logger.debug(self.sScreen3Row2)

            time.sleep(0.5)
Example #14
0
def estimate_volume(equator_filename, poles_filename):
    """
    Args:
        equator_filename:
        poles_filename: 
    
    Returns:
        
    """
    diameters = []
    for fn in equator_filename, poles_filename:
        processer = \
            Processer(f'{fn}{EXT}', TARGET_WIDTH, CAL_MTX, DIST, debug=DEBUG)

        #######################################################################
        # Find squares centroids
        #######################################################################
        im = (
            processer
                .undistort()
                .resize()
                .blur(3)
                .get_processed_image()
        )

        squares_centroids = find_squares(im)


        #######################################################################
        # Find Orange
        #######################################################################
        im = (
            processer
                .show("Orange")
                .perspective_transform(squares_centroids)
                .show("Orange")
                .to_hsv()
                .show("Orange")
                .filter_by_hsv_color(lowHSV=HSV_LOW, highHSV=HSV_HIGH)
                .show("Orange")
                .negate()
                .show("Orange")
                .open(size=3, iterations=10, element='circle')
                .close(size=7, iterations=7, element='circle')
                .show("Orange")
                # TODO: show thresholded orange instead of the blob
                .get_processed_image()
        )

        orange_kpts, orange_diam_px = find_orange(im)
        orange_centroids = np.array([kp.pt for kp in orange_kpts])


        #######################################################################
        # Transform pixels to mm
        #######################################################################
        height_px, width_px = im.shape
        px_per_mm_height = height_px / REAL_H
        px_per_mm_width = width_px / REAL_W
        logger.debug(f'{px_per_mm_height:.1f} px/mm [height]')
        logger.debug(f'{px_per_mm_width:.1f} px/mm [width]')

        orange_diameter = calc_orange_real_diam(ref_mm=REAL_H, 
                                                ref_px=height_px, 
                                                orange_diam_px=orange_diam_px, 
                                                focal_length_px=FOCAL_LENGTH_PX)
        
        logger.debug(f'Focal length: {FOCAL_LENGTH_PX:.1f} px')
        logger.debug(f'Image orange diameter: {orange_diam_px:.1f} px')
        logger.info(f'Estimated real orange diameter: {orange_diameter:.1f} mm')

        #######################################################################
        # Draw
        #######################################################################
        im = (
                processer
                    .undistort()
                    .reset()
                    .resize()
                    .perspective_transform(squares_centroids)
                    .get_processed_image()
            )

        # Mark the orange
        im_with_keypoints = drawKeyPts(im, orange_kpts, (0,0,255), 10)

        # Draw lines between squares
        # tl, tr, br, bl = order_points(squares_centroids)
        # draw_line_with_long(im_with_keypoints, tl, tr, mm_per_px1)
        # draw_line_with_long(im_with_keypoints, br, tr, mm_per_px1)
        # draw_line_with_long(im_with_keypoints, bl, br, mm_per_px1)
        # draw_line_with_long(im_with_keypoints, bl, tl, mm_per_px1)

        # Draw orange diameter
        orange_diam_text_x = int(orange_centroids[0][0])
        orange_diam_text_y = int(orange_centroids[0][1] - (orange_diam_px / 2) - 10)
        cv2.putText(im_with_keypoints,
                    text = f"{orange_diameter:.1f} mm", 
                    org = (orange_diam_text_x, orange_diam_text_y), 
                    fontFace = cv2.FONT_HERSHEY_SIMPLEX, 
                    fontScale = 3.5, 
                    color = (0,0,255), 
                    thickness = 5)

        cv2.imwrite(f'{fn}-out{EXT}', im_with_keypoints)
        diameters.append(orange_diameter)
        logger.info(f'Finished with one orange.')
    
    ###########################################################################
    # FINAL CALC
    ###########################################################################
    orange_volume = calculate_orange_volume(diameters[0], diameters[1])
    logger.info(f'Finished with orange {equator_filename}, {poles_filename}')
    logger.info(f'Estimated real orange volume: {orange_volume:.1f} ml\n')
    return orange_volume
Example #15
0
 def stopHeatingCooling(self):
     sTime = datetime.datetime.now().strftime("%d.%m.%Y %H:%M:%S")
     logger.debug("("+sTime+"): Turned Off")
     self.ser.write(b'O\n')
Example #16
0
 def _updateState(self):
     sTime = datetime.datetime.now().strftime("%d.%m.%Y %H:%M:%S")
     logger.debug("("+sTime+"): Status request")
     self.ser.write(b'?\n')
Example #17
0
    def _readdata(self):

        curTime = datetime.now()
        timeout = curTime + timedelta(
            minutes=1)  # scan for 1 minute looking for data from tilt

        logger.debug("Connecting to Bluetooth...")
        try:
            sock = bluez.hci_open_dev(self.bluetoothDeviceId)

        except:
            logger.exception("Error accessing bluetooth device...")
            return False

        blescan.hci_le_set_scan_parameters(sock)
        blescan.hci_enable_le_scan(sock)

        gotData = 0

        while (gotData == 0 and curTime < timeout):
            returnedList = blescan.parse_events(sock, 10)

            for beacon in returnedList:  # returnedList is a list datatype of string datatypes seperated by commas (,)

                output = beacon.split(
                    ',')  # split the list into individual strings in an array
                uuid = output[1]

                if uuid in Tilt.color.keys():
                    logger.debug("Found Tilt hydrometer:" + uuid)
                    gotData = 1
                    foundColor = Tilt.color.get(uuid)
                    foundTemp = float(int(output[2], 16) - 32) * 5 / 9
                    foundSG = float(int(output[3], 16) / 1000)

                    logger.debug("Found " + foundColor + " Tilt: T/" +
                                 str(foundTemp) + ", SG/" + str(foundSG))

                    if foundColor != self.color:
                        logger.debug(
                            "Skipping data; wrong color Tilt. Looking for: " +
                            self.color)
                        gotData = 0  # wrong tilt
                    elif foundTemp > 200:  # first reading always showed temperature of 537.2C and SG 1.0
                        logger.debug(
                            "Skipping initial datasets as temp and SG are always wrong"
                        )
                        timeout = curTime + timedelta(
                            minutes=1
                        )  # extend timeout looking for valid data from tilt
                        gotData = 0  # forces to continue reading from tilt looking for valid data
                    else:
                        self._storeData(foundTemp, foundSG, curTime)
                        logger.info(self.color + " - " +
                                    curTime.strftime(DATETIME_FORMAT) +
                                    " - T:" + str(round(float(foundTemp), 1)) +
                                    " - SG:" +
                                    "{:5.3f}".format(round(float(foundSG), 3)))

            curTime = datetime.now()

        # Did not collect data before timeout; set data as invalid
        if gotData == 0:
            logger.debug("Timed out collecting data from Tilt")

        blescan.hci_disable_le_scan(sock)
        return True
Example #18
0
    def _evaluate(self):
        self.control
        self.targetTemps
        self.tempDates
        self.bufferBeerTemp
        self.bufferChamberScale

        # use wired data initially
        if self.control.isDataValid():
            self.beerTemp = self.control.getBeerTemp()
            self.beerWireTemp = self.control.getBeerTemp()
            self.chamberTemp = self.control.getChamberTemp()
            self.timeData = self.control.timeOfData()
        else:
            self.beerTemp = DEFAULT_TEMP
            self.beerWireTemp = DEFAULT_TEMP
            self.chamberTemp = DEFAULT_TEMP

            self.control.stopHeatingCooling()
            logger.error(
                "Chamber paused (60s), heating and cooling stopped: controller data is invalid"
            )
            self.paused = True
            time.sleep(PAUSE_DELAY)
            return

        # if Tilt is configured and available replace related values
        if (self.tilt is not None):
            tiltdatatime = self.tilt.timeOfData()
            if tiltdatatime is not None and tiltdatatime > datetime.datetime.now(
            ) - datetime.timedelta(minutes=5):
                self.beerTemp = self.tilt.getTemp()
                self.beerSG = self.tilt.getGravity()
                if self.timeData < tiltdatatime:
                    self.timeData = tiltdatatime
            else:
                self.beerSG = DEFAULT_SG
                logger.error(
                    "Data from tilt unavailable, checking again in 60s: using wired temperatures"
                )
                time.sleep(PAUSE_DELAY)

        self.paused = False
        _curTime = datetime.datetime.now()

        # check which of the temperature change dates have passed
        datesPassed = 0
        for dt in self.tempDates:
            if dt < _curTime:
                datesPassed = datesPassed + 1

        # No configured dates have passed, leave chamer powered off
        if datesPassed == 0:
            # Turn off heating and cooling
            logger.debug(
                "Leaving chamber heating/cooling off until first date reached: "
                + self.tempDates[datesPassed].strftime("%d.%m.%Y %H:%M:%S"))
            self.control.stopHeatingCooling()
            return

        # check if last date has been reached. If so, heating/cooling should stop
        elif datesPassed == len(self.tempDates):
            logger.debug("Last date reached turning heating/cooling off: " +
                         self.tempDates[datesPassed -
                                        1].strftime("%d.%m.%Y %H:%M:%S"))
            self.control.stopHeatingCooling()
            return

        # date is within configured range
        else:
            self.targetTemp = self.targetTemps[datesPassed - 1]

            # beer is warmer than target + buffer, consider cooling
            if self.beerTemp > (self.targetTemp + self.bufferBeerTemp):
                # check how much cooler chamber is compared to target, do not want it too low or beer temperature will overshoot too far.
                if (self.targetTemp -
                        self.chamberTemp) < self.bufferChamberScale * (
                            self.beerTemp - self.targetTemp):
                    # Turn cooling ON
                    logger.debug("Cooling to be turned ON - Target: " +
                                 str(self.targetTemp) + "; Beer: " +
                                 str(self.beerTemp) + "; Chamber: " +
                                 str(self.chamberTemp) + "; Beer Buffer: " +
                                 str(self.bufferBeerTemp) +
                                 "; Chamber Scale: " +
                                 str(self.bufferChamberScale))
                    self.control.startCooling()
                else:
                    logger.debug("Chamber is cold enough to cool beer")
                    self.control.stopHeatingCooling()

            # beer is cooler than target + buffer, consider heating
            elif self.beerTemp < (self.targetTemp - self.bufferBeerTemp):
                # check how much hotter chamber is compared to target, do not want it too high or beer temperature will overshoot too far.
                if (self.chamberTemp -
                        self.targetTemp) < self.bufferChamberScale * (
                            self.targetTemp - self.beerTemp):
                    # Turn heating ON
                    logger.debug("Heating to be turned ON - Target: " +
                                 str(self.targetTemp) + "; Beer: " +
                                 str(self.beerTemp) + "; Chamber: " +
                                 str(self.chamberTemp) + "; Beer Buffer: " +
                                 str(self.bufferBeerTemp) +
                                 "; Chamber Scale: " +
                                 str(self.bufferChamberScale))
                    self.control.startHeating()
                else:
                    logger.debug("Chamber is warm enough to heat beer")
                    self.control.stopHeatingCooling()

            # beer is within range of target +/- buffer
            else:
                logger.debug("No heating/cooling needed - Target: " +
                             str(self.targetTemp) + "; Beer: " +
                             str(self.beerTemp) + "; Chamber: " +
                             str(self.chamberTemp) + "; Beer Buffer: " +
                             str(self.bufferBeerTemp) + "; Chamber Scale: " +
                             str(self.bufferChamberScale))
                self.control.stopHeatingCooling()
        return
Example #19
0
    def _readConf(self):

        try:
            if os.path.isfile(CONFIGFILE) == False:
                logger.error("BrewFather configuration file is not valid: " +
                             CONFIGFILE)

            ini = configparser.ConfigParser()
            ini.read(CONFIGFILE)

            if 'BrewFather' in ini:
                logger.debug("Reading BrewFather config")

                config = ini['BrewFather']

                try:
                    if config["MessageLevel"] == "DEBUG":
                        logger.setLevel(logging.DEBUG)
                    elif config["MessageLevel"] == "WARNING":
                        logger.setLevel(logging.WARNING)
                    elif config["MessageLevel"] == "ERROR":
                        logger.setLevel(logging.ERROR)
                    elif config["MessageLevel"] == "INFO":
                        logger.setLevel(logging.INFO)
                    else:
                        logger.setLevel(logging.INFO)
                except KeyError:
                    logger.setLevel(logging.INFO)

                if config["Update"] != "":
                    self.bUpdate = strtobool(config.get("Update"))
                else:
                    raise Excpetion
                if config["UpdateURL"] != "":
                    self.sURL = config.get("UpdateURL")
                else:
                    raise Exception

                try:
                    if config["UpdateIntervalSeconds"] != "":
                        if int(config["UpdateIntervalSeconds"]
                               ) >= MINIMUM_INTERVAL:
                            self.interval = int(
                                config.get("UpdateIntervalSeconds"))
                        else:
                            logger.warning(
                                "Brewfather update interval cannot be less than 15min; using 900s"
                            )
                            self.interval = MINIMUM_INTERVAL
                    else:
                        raise Exception
                except:
                    logger.warning(
                        "Error reading Brewfather update interval; using 900s")
                    self.interval = MINIMUM_INTERVAL

                try:
                    if config["Device"] != "":
                        self.postdata["name"] = config["Device"]
                    else:
                        raise Exception
                except:
                    self.postdata["name"] = "Fermonitor"

        except:
            self.bUpdate = False
            logger.warning(
                "Problem read from configuration file: " + CONFIGFILE +
                ". Updating BrewFather.app is disabled until configuration fixed. It could take a minute for updated values in config file to be used."
            )
            print("[BrewFather]\nUpdate = " + str(self.bUpdate) +
                  "\nUpdateURL = " + self.sURL + "\nUpdateIntervalSeconds = " +
                  str(self.interval))

        logger.debug("BrewFather config:\n[BrewFather]\nUpdate = " +
                     str(self.bUpdate) + "\nUpdateURL = " + self.sURL +
                     "\nUpdateIntervalSeconds = " + str(self.interval))
Example #20
0
def read_settings():
    global sTiltColor
    global chamberControlTemp
    global bUseTilt
    global logLevel

    chamberControlTemp = CONTROL_WIRE
    bUseTilt = False
    logLevel = logging.INFO

    logger.debug("Reading configfile: " + CONFIGFILE)

    try:
        if os.path.isfile(CONFIGFILE) == False:
            raise Exception

        ini = configparser.ConfigParser()
        ini.read(CONFIGFILE)
    except:
        raise IOError("Fermonitor configuration file is not valid: " +
                      CONFIGFILE)

    try:
        config = ini['Fermonitor']
    except:
        raise IOError("[Fermonitor] section not found in fermonitor.ini")

    try:
        if config["MessageLevel"] == "DEBUG":
            logLevel = logging.DEBUG
        elif config["MessageLevel"] == "WARNING":
            logLevel = logging.WARNING
        elif config["MessageLevel"] == "ERROR":
            logLevel = logging.ERROR
        elif config["MessageLevel"] == "INFO":
            logLevel = logging.INFO
        else:
            logLevel = logging.INFO
    except KeyError:
        logLevel = logging.INFO

    logger.setLevel(logLevel)

    try:
        if config["TiltColor"] != "":
            sTiltColor = config.get("TiltColor")
        else:
            raise Exception
    except:
        logger.warning("No color specified for Tilt. Tilt not used.")
        sTiltColor = ""

    logger.debug("Tilt color: " + sTiltColor)

    try:
        if config["ChamberControl"] != "":
            if config.get("ChamberControl") == "WIRE":
                chamberControlTemp = CONTROL_WIRE
                logger.debug("Chamber control temperature based on WIRE")
            elif config.get("ChamberControl") == "TILT":
                chamberControlTemp = CONTROL_TILT
                logger.debug("Chamber control temperature based on TILT")
            else:
                chamberControlTemp = CONTROL_WIRE
                logger.warning(
                    "Invalid ChamberControl configuration; using default: WIRE"
                )
        else:
            chamberControlTemp = CONTROL_WIRE
            logger.warning(
                "Invalid ChamberControl configuration; using default: WIRE")
    except:
        chamberControlTemp = CONTROL_WIRE
        logger.warning(
            "Invalid ChamberControl configuration; using default: WIRE")

    try:
        if config["MessageLevel"] == "DEBUG":
            logLevel = logging.DEBUG
        elif config["MessageLevel"] == "WARNING":
            logLevel = logging.WARNING
        elif config["MessageLevel"] == "ERROR":
            logLevel = logging.ERROR
        elif config["MessageLevel"] == "INFO":
            logLevel = logging.INFO
        else:
            logLevel = logging.INFO
    except KeyError:
        logLevel = logging.INFO

    logger.setLevel(logLevel)

    logger.debug("Completed reading settings")
    return
Example #21
0
def main():

    global timeBeer
    global target
    global tempBeer
    global tempChamber
    global tempBeerWire
    global gravity
    global cTilt
    global cChamber
    global cBrewfather

    logger.info("Starting Fermonitor...")

    read_settings()

    cInterface = interface.Interface("Fermonitor......")
    cInterface.setLogLevel(logLevel)
    cInterface.start()

    cChamber = chamber.Chamber(None)
    cChamber.start()

    cTilt = None

    # Start BrewFather thread to store temp and gravity
    logger.debug("Starting BrewFather Thread")
    cBrewfather = brewfather.BrewFather()
    cBrewfather.start()

    # Main loop for reading and logging data as well as controllng fermentor
    while True:

        read_settings()
        cInterface.setLogLevel(logLevel)

        # Handle Tilt

        if sTiltColor != "":
            if (cTilt is not None) and (cTilt.getColor() != sTiltColor):
                logger.debug("Tilt color changed: stopping Tilt: " +
                             cTilt.getColor())
                cTilt = None

            if cTilt is None:
                logger.debug("Starting Tilt monitoring: " + sTiltColor)
                cTilt = tilt.Tilt(sTiltColor)
                cTilt.start()
                time.sleep(10)

        else:
            cTilt = None

        if chamberControlTemp == CONTROL_TILT:
            cChamber.setTilt(cTilt)
        else:
            cChamber.setTilt(None)

        if not cChamber.paused:
            target = cChamber.getTargetTemp()
            tempBeer = cChamber.getBeerTemp()
            tempBeerWire = cChamber.getWireBeerTemp()
            tempChamber = cChamber.getChamberTemp()
            timeBeer = cChamber.timeOfData()
            if cTilt is not None:
                datatime = cTilt.timeOfData()
                if datatime is not None and datatime > datetime.datetime.now(
                ) - datetime.timedelta(minutes=5):
                    gravity = cTilt.getGravity()
            else:
                gravity = None

            cBrewfather.setData(tempBeer, tempChamber, gravity)

            cInterface.setData(target, tempBeer, gravity, tempBeerWire,
                               tempChamber)

        else:
            timeBeer = None
            target = None
            tempBeer = None
            tempChamber = None
            tempBeerWire = None

        time.sleep(1)
Example #22
0
 def __del__(self):
     logger.debug("Delete controller class")
Example #23
0
    def _processControllerResponse(self, str):
        try:
            curTime = datetime.datetime.now()
            sTime =  self.lastUpdateTime.strftime("%d.%m.%Y %H:%M:%S")

            lhs, rhs = str.split(":", 1)
            if lhs == "C":
                if rhs == "-":
                    logger.debug("("+sTime+"): Cooling is OFF")
                    if self.bCoolOn == True:
                        self.coolEndTime = curTime
                    self.bCoolOn = False
                elif rhs == "+":
                    logger.debug("("+sTime+"): Cooling is ON")
                    self.bCoolOn = True
            elif lhs == "H":
                if rhs == "-":
                    logger.debug("("+sTime+"): Heating is OFF")
                    if self.bHeatOn == True:
                        self.heatEndTime = curTime
                    self.bHeatOn = False
                elif rhs == "+":
                    logger.debug("("+sTime+"): Heating is ON")
                    self.bHeatOn = True
            elif lhs == "F":
                self.chamberTemp = float(rhs)
                logger.debug("("+sTime+"): Fridge temperature: {:5.3f}C".format(round(float(self.getChamberTemp()),1)))
                self.lastUpdateTime = curTime
            elif lhs == "B":
                self.beerTemp = float(rhs)
                logger.debug("("+sTime+"): Beer temperature: {:5.3f}C".format(round(float(self.getBeerTemp()),1)))
                self.lastUpdateTime = curTime
            elif lhs == "S":
                self.internalTemp = float(rhs)
                logger.debug("("+sTime+"): Delta to safety temperature: "+rhs+"C")
                self.lastUpdateTime = curTime

        except BaseException as e:
            logger.error("ERROR: %s\n" % str(e))
Example #24
0
    def _readConf(self):

        bDefaultInterval = True
        bDefaultBtDeviceId = True

        if os.path.isfile(CONFIGFILE) == False:
            logger.error("Tilt configuration file is not valid: " + CONFIGFILE)
        else:
            ini = configparser.ConfigParser()
            try:
                logger.debug("Reading Tilt config: " + CONFIGFILE)
                ini.read(CONFIGFILE)

                if self.color in ini:
                    config = ini[self.color]

                    try:
                        if config["UpdateIntervalSeconds"] != "" and int(
                                config["UpdateIntervalSeconds"]
                        ) >= MINIMUM_INTERVAL:
                            self.interval = int(
                                config.get("UpdateIntervalSeconds"))
                            bDefaultInterval = False
                        else:
                            self.interval = MINIMUM_INTERVAL
                    except KeyError:
                        pass

                    try:
                        if config["BluetoothDeviceId"] != "" and int(
                                config["BluetoothDeviceId"]) >= 0:
                            self.bluetoothDeviceId = int(
                                config.get("BluetoothDeviceId"))
                            bDefaultBtDeviceId = False
                        else:
                            self.bluetoothDeviceId = 0
                    except KeyError:
                        pass

                    try:
                        if config["MessageLevel"] == "DEBUG":
                            logger.setLevel(logging.DEBUG)
                        elif config["MessageLevel"] == "WARNING":
                            logger.setLevel(logging.WARNING)
                        elif config["MessageLevel"] == "ERROR":
                            logger.setLevel(logging.ERROR)
                        elif config["MessageLevel"] == "INFO":
                            logger.setLevel(logging.INFO)
                        else:
                            logger.setLevel(logging.INFO)
                    except KeyError:
                        logger.setLevel(logging.INFO)
                else:
                    logger.error("[" + self.color +
                                 "] section not found in ini file: " +
                                 CONFIGFILE)
            except:
                pass

        if bDefaultInterval or bDefaultBtDeviceId:
            logger.warning("Problem read from configuration file: \""+CONFIGFILE+ \
                "\". Using some default values[**] for Tilt configuration. It could take a minute for updated values in config file to be used.")
            sConf = "Color = " + self.color
            sConf = sConf + "\nUpdateIntervalSeconds = " + str(self.interval)
            if bDefaultInterval:
                sConf = sConf + "**"
            sConf = sConf + "\nBluetoothDeviceId = " + str(
                self.bluetoothDeviceId)
            if bDefaultBtDeviceId:
                sConf = sConf + "**"
            print(sConf)
Example #25
0
 def __del__(self):
     self.lcd.lcd_clear()
     self.lcd.backlight(0)
     logger.debug("Delete interface class")