예제 #1
0
    def save_settings_to_file(self):
        # This is format" "2019-01-08-16-50-15"
        oldSettingsFileName = 'settings-{0}.json'.format(time.strftime("%Y-%m-%dT%H-%M-%S"))
        settingsBackupDir = '{0}settings/controller-backup/'.format(util.addSlash(util.scriptPath()))
        if not os.path.exists(settingsBackupDir):
            os.makedirs(settingsBackupDir)

        # Set owner and permissions for directory
        fileMode = stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH | stat.S_IXOTH # 775
        owner = 'brewpi'
        group = 'brewpi'
        uid = pwd.getpwnam(owner).pw_uid
        gid = grp.getgrnam(group).gr_gid
        os.chown(settingsBackupDir, uid, gid) # chown dir
        os.chmod(settingsBackupDir, fileMode) # chmod dir

        oldSettingsFilePath = os.path.join(
            settingsBackupDir, oldSettingsFileName)
        oldSettingsFile = open(oldSettingsFilePath, 'w')
        oldSettingsFile.write(json.dumps(self.oldSettings))
        oldSettingsFile.truncate()
        oldSettingsFile.close()

        # Set owner and permissions for file
        fileMode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP # 660
        owner = 'brewpi'
        group = 'brewpi'
        uid = pwd.getpwnam(owner).pw_uid
        gid = grp.getgrnam(group).gr_gid
        os.chown(oldSettingsFilePath, uid, gid) # chown file
        os.chmod(oldSettingsFilePath, fileMode) # chmod file

        printStdErr("\nSaved old settings to file {0}.".format(oldSettingsFileName))
예제 #2
0
    def parseProcess(self, process):
        """
        Converts a psutil process into a BrewPiProcess object by parsing the config file it has been called with.
        Params: a psutil.Process object
        Returns: BrewPiProcess object
        """
        bp = BrewPiProcess()
        db_config = None
        cfg = None
        try:
            bp.pid = process._pid
            try:  # If this is a database configured installation, try loading via the process ID
                db_config = models.BrewPiDevice.objects.get(process_id=bp.pid)
            except:
                cfg = [s for s in process.cmdline()
                       if '.cfg' in s]  # get config file argument
        except psutil.NoSuchProcess:
            # process no longer exists
            return None
        if db_config is not None:  # If this is a database-configured installation, use the database configuration
            bp.cfg = util.read_config_from_database_without_defaults(db_config)
        else:
            if cfg:
                cfg = cfg[0]  # add full path to config file
            else:
                # use default config file location
                cfg = util.scriptPath() + "/settings/config.cfg"
            bp.cfg = util.read_config_file_with_defaults(cfg)

        bp.port = bp.cfg['port']
        bp.sock = BrewPiSocket.BrewPiSocket(bp.cfg)
        return bp
예제 #3
0
def stopLogging():
    global config
    logMessage("Stopped data logging, as requested in web interface. " +
               "BrewPi will continue to control temperatures, but will not log any data.")
    config = util.configSet(configFile, 'beerName', None)
    config = util.configSet(configFile, 'dataLogging', 'stopped')
    changeWwwSetting('beerName', None)
    return {'status': 0, 'statusMessage': "Successfully stopped logging"}
예제 #4
0
def stopLogging():
    global config
    logMessage("Stopped data logging, as requested in web interface. " +
               "BrewPi will continue to control temperatures, but will not log any data.")
    config = util.configSet(configFile, 'beerName', None)
    config = util.configSet(configFile, 'dataLogging', 'stopped')
    changeWwwSetting('beerName', None)
    return {'status': 0, 'statusMessage': "Successfully stopped logging"}
예제 #5
0
def startNewBrew(newName):
    global config
    if len(newName) > 1:     # shorter names are probably invalid
        config = util.configSet(configFile, 'beerName', newName)
        config = util.configSet(configFile, 'dataLogging', 'active')
        startBeer(newName)
        logMessage("Notification: Restarted logging for beer '%s'." % newName)
        return {'status': 0, 'statusMessage': "Successfully switched to new brew '%s'. " % urllib.unquote(newName) +
                                              "Please reload the page."}
    else:
        return {'status': 1, 'statusMessage': "Invalid new brew name '%s', "
                                              "please enter a name with at least 2 characters" % urllib.unquote(newName)}
예제 #6
0
def startNewBrew(newName):
    global config
    if len(newName) > 1:     # shorter names are probably invalid
        config = util.configSet(configFile, 'beerName', newName)
        config = util.configSet(configFile, 'dataLogging', 'active')
        startBeer(newName)
        logMessage("Notification: Restarted logging for beer '%s'." % newName)
        return {'status': 0, 'statusMessage': "Successfully switched to new brew '%s'. " % urllib.unquote(newName) +
                                              "Please reload the page."}
    else:
        return {'status': 1, 'statusMessage': "Invalid new brew name '%s', "
                                              "please enter a name with at least 2 characters" % urllib.unquote(newName)}
예제 #7
0
 def __init__(self, host=None, port=None):
     self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     # find BrewPi's via mdns lookup
     self.host=host
     self.port=port
     self.retries=10 # max reconnect attempts to try when doing a read or write operation
     self.retryCount=0 # count of reconnect attempts performed
     BrewPiUtil.logMessage("Connecting to BrewPi " + host + " on port " + str(port))
     self.open()
     self.setTimeout(0.5)
     # self.timeout=self.sock.gettimeout()
     self.name=host + ':' + str(port)
     return      
예제 #8
0
def setFiles():
    global config
    global localJsonFileName
    global localCsvFileName
    global wwwJsonFileName
    global wwwCsvFileName
    global lastDay
    global day

    # create directory for the data if it does not exist
    beerFileName = config['beerName']
    dataPath = util.addSlash(
        util.addSlash(util.scriptPath()) + 'data/' + beerFileName)
    wwwDataPath = util.addSlash(
        util.addSlash(config['wwwPath']) + 'data/' + beerFileName)

    if not os.path.exists(dataPath):
        os.makedirs(dataPath)
        os.chmod(dataPath, 0775)  # give group all permissions
    if not os.path.exists(wwwDataPath):
        os.makedirs(wwwDataPath)
        os.chmod(wwwDataPath, 0775)  # give group all permissions

    # Keep track of day and make new data file for each day
    day = time.strftime("%Y-%m-%d")
    lastDay = day
    # define a JSON file to store the data
    jsonFileName = beerFileName + '-' + day

    #if a file for today already existed, add suffix
    if os.path.isfile(dataPath + jsonFileName + '.json'):
        i = 1
        while os.path.isfile(dataPath + jsonFileName + '-' + str(i) + '.json'):
            i += 1
        jsonFileName = jsonFileName + '-' + str(i)

    localJsonFileName = dataPath + jsonFileName + '.json'
    brewpiJson.newEmptyFile(localJsonFileName)

    # Define a location on the web server to copy the file to after it is written
    wwwJsonFileName = wwwDataPath + jsonFileName + '.json'

    # Define a CSV file to store the data as CSV (might be useful one day)
    localCsvFileName = (dataPath + beerFileName + '.csv')
    wwwCsvFileName = (wwwDataPath + beerFileName + '.csv')

    # create new empty json file
    brewpiJson.newEmptyFile(localJsonFileName)
예제 #9
0
def getNewTemp(scriptPath):
    with open(util.addSlash(scriptPath) + 'settings/tempProfile.csv',
              'rU') as csvfile:
        dialect = csv.Sniffer().sniff(csvfile.readline())
        csvfile.seek(0)
        temperatureReader = csv.reader(csvfile, dialect)
        next(temperatureReader
             )  # Discard the first row, which is the table header
        prevTemp = None
        nextTemp = None
        interpolatedTemp = -99
        prevDate = None
        nextDate = None

        now = time.mktime(
            time.localtime())  # Get current time in seconds since epoch

        for row in temperatureReader:
            dateString = row[0]
            try:
                date = time.mktime(
                    time.strptime(dateString, "%Y-%m-%dT%H:%M:%S"))
            except ValueError:
                continue  # Skip dates that cannot be parsed

            try:
                temperature = float(row[1])
            except ValueError:
                if row[1].strip() == '':
                    # Cell is left empty, this is allowed to disable temperature control in part of the profile
                    temperature = None
                else:
                    # Invalid number string, skip this row
                    continue

            prevTemp = nextTemp
            nextTemp = temperature
            prevDate = nextDate
            nextDate = date
            timeDiff = now - nextDate
            if timeDiff < 0:
                if prevDate is None:
                    interpolatedTemp = nextTemp  # First set point is in the future
                    break
                else:
                    if prevTemp is None or nextTemp is None:
                        # When the previous or next temperature is an empty cell, disable temperature control.
                        # This is useful to stop temperature control after a while or to not start right away.
                        interpolatedTemp = None
                    else:
                        interpolatedTemp = ((now - prevDate) /
                                            (nextDate - prevDate) *
                                            (nextTemp - prevTemp) + prevTemp)
                        interpolatedTemp = round(interpolatedTemp, 2)
                    break

        if interpolatedTemp == -99:  # All set points in the past
            interpolatedTemp = nextTemp

        return interpolatedTemp
 def open_serial(self, config, baud, timeout):
     self.close_bg_serial()
     if self.ser is None:
         self.ser = util.setupSerial(config, baud, timeout)
         if self.ser is None:
             return False
     return True
예제 #11
0
    def retrieve_settings_from_serial(self):
        ser = self.ser
        self.oldSettings.clear()
        printStdErr("Requesting old settings from %(a)s..." % msg_map)
        expected_responses = 2
        if not self.versionOld.isNewer("0.2.0"):  # versions older than 2.0.0 did not have a device manager
            expected_responses += 1
            ser.write("d{}")  # installed devices
            time.sleep(1)
        ser.write("c")  # control constants
        ser.write("s")  # control settings
        time.sleep(2)

        while expected_responses:
            line = ser.readline()
            if line:
                line = util.asciiToUnicode(line)
                if line[0] == 'C':
                    expected_responses -= 1
                    self.oldSettings['controlConstants'] = json_decode_response(line)
                elif line[0] == 'S':
                    expected_responses -= 1
                    self.oldSettings['controlSettings'] = json_decode_response(line)
                elif line[0] == 'd':
                    expected_responses -= 1
                    self.oldSettings['installedDevices'] = json_decode_response(line)
예제 #12
0
    def parseProcess(self, process):
        """
        Converts a psutil process into a BrewPiProcess object by parsing the
        config file it has been called with.
            :Params:    A psutil.Process object
            :Returns:   A BrewPiProcess object
        """
        bp = BrewPiProcess()
        try:
            bp.pid = process._pid
            cfg = [s for s in process.cmdline()
                   if '.cfg' in s]  # get config file argument
            # Get brewpi.py file argument so we can grab path
            bps = [s for s in process.cmdline() if 'brewpi.py' in s]
        except psutil.NoSuchProcess:
            # process no longer exists
            return None

        if cfg:
            cfg = cfg[0]  # add full path to config file
        else:
            # Get path from arguments and use that to build default path to config
            cfg = os.path.dirname(str(bps)).translate(
                str.maketrans('', '', r"[]'")) + '/settings/config.cfg'
        bp.cfg = util.readCfgWithDefaults(cfg)
        if bp.cfg['port'] is not None:
            bp.port = bp.cfg['port']
        bp.sock = BrewPiSocket.BrewPiSocket(bp.cfg)
        return bp
예제 #13
0
    def retrieve_settings_from_serial(self):
        ser = self.ser
        self.oldSettings.clear()
        printStdErr("\nRequesting old settings from %(a)s." % msg_map)
        expected_responses = 2
        # versions older than 2.0.0 did not have a device manager
        if not self.versionOld.isNewer("0.2.0"):
            expected_responses += 1
            ser.write("d{}".encode())  # installed devices
            time.sleep(1)
        ser.write("c".encode())  # control constants
        ser.write("s".encode())  # control settings
        time.sleep(2)

        while expected_responses:
            line = ser.readline().decode()
            if line:
                line = util.asciiToUnicode(str(line))
                if line[0] == 'C':
                    expected_responses -= 1
                    self.oldSettings['controlConstants'] = json_decode_response(
                        line)
                elif line[0] == 'S':
                    expected_responses -= 1
                    self.oldSettings['controlSettings'] = json_decode_response(
                        line)
                elif line[0] == 'd':
                    expected_responses -= 1
                    self.oldSettings['installedDevices'] = json_decode_response(
                        line)
예제 #14
0
 def open_serial(self, config, baud, timeout):
     if self.ser:
         self.ser.close()
     self.ser = None
     self.ser = util.setupSerial(config, baud, timeout, 1.0, True)
     if self.ser is None:
         return False
     return True
예제 #15
0
def resumeLogging():
    global config
    logMessage("Continued logging data, as requested in web interface.")
    if config['dataLogging'] == 'paused':
        config = util.configSet(configFile, 'dataLogging', 'active')
        return {'status': 0, 'statusMessage': "Successfully continued logging."}
    else:
        return {'status': 1, 'statusMessage': "Logging was not paused."}
예제 #16
0
def resumeLogging():
    global config
    logMessage("Continued logging data, as requested in web interface.")
    if config['dataLogging'] == 'paused':
        config = util.configSet(configFile, 'dataLogging', 'active')
        return {'status': 0, 'statusMessage': "Successfully continued logging."}
    else:
        return {'status': 1, 'statusMessage': "Logging was not paused."}
예제 #17
0
 def open_serial(self, config, baud, timeout):
     if self.ser:
         self.ser.close()
     self.ser = None
     self.ser = util.setupSerial(config, baud, timeout)
     if self.ser is None:
         return False
     return True
예제 #18
0
def setFiles():
    global config
    global localJsonFileName
    global localCsvFileName
    global wwwJsonFileName
    global wwwCsvFileName
    global lastDay
    global day

    # create directory for the data if it does not exist
    beerFileName = config['beerName']
    dataPath = util.addSlash(util.addSlash(util.scriptPath()) + 'data/' + beerFileName)
    wwwDataPath = util.addSlash(util.addSlash(config['wwwPath']) + 'data/' + beerFileName)

    if not os.path.exists(dataPath):
        os.makedirs(dataPath)
        os.chmod(dataPath, 0775)  # give group all permissions
    if not os.path.exists(wwwDataPath):
        os.makedirs(wwwDataPath)
        os.chmod(wwwDataPath, 0775)  # give group all permissions

    # Keep track of day and make new data file for each day
    day = time.strftime("%Y-%m-%d")
    lastDay = day
    # define a JSON file to store the data
    jsonFileName = beerFileName + '-' + day

    #if a file for today already existed, add suffix
    if os.path.isfile(dataPath + jsonFileName + '.json'):
        i = 1
        while os.path.isfile(dataPath + jsonFileName + '-' + str(i) + '.json'):
            i += 1
        jsonFileName = jsonFileName + '-' + str(i)

    localJsonFileName = dataPath + jsonFileName + '.json'
    brewpiJson.newEmptyFile(localJsonFileName)

    # Define a location on the web server to copy the file to after it is written
    wwwJsonFileName = wwwDataPath + jsonFileName + '.json'

    # Define a CSV file to store the data as CSV (might be useful one day)
    localCsvFileName = (dataPath + beerFileName + '.csv')
    wwwCsvFileName = (wwwDataPath + beerFileName + '.csv')

    # create new empty json file
    brewpiJson.newEmptyFile(localJsonFileName)
예제 #19
0
def pauseLogging():
    global config
    logMessage("Paused logging data, as requested in web interface. " +
               "BrewPi will continue to control temperatures, but will not log any data until resumed.")
    if config['dataLogging'] == 'active':
        config = util.configSet(configFile, 'dataLogging', 'paused')
        return {'status': 0, 'statusMessage': "Successfully paused logging."}
    else:
        return {'status': 1, 'statusMessage': "Logging already paused or stopped."}
예제 #20
0
	def create(self):
		""" Creates a socket socket based on the settings in the member variables and assigns it to self.sock
		This function deletes old sockets for file sockets, so do not use it to connect to a socket that is in use.
		"""
		if self.type == 'i':  # Internet socket
			self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
			self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
			self.sock.bind((self.host, self.port))
			util.logMessage('Bound to TCP socket on port %d ' % self.port)
		else:
			if os.path.exists(self.file):
				# if socket already exists, remove it. This prevents  errors when the socket is corrupt after a crash.
				os.remove(self.file)
			self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
			self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
			self.sock.bind(self.file)  # Bind BEERSOCKET
			# set all permissions for socket
			os.chmod(self.file, 0777)
예제 #21
0
def pauseLogging():
    global config
    logMessage("Paused logging data, as requested in web interface. " +
               "BrewPi will continue to control temperatures, but will not log any data until resumed.")
    if config['dataLogging'] == 'active':
        config = util.configSet(configFile, 'dataLogging', 'paused')
        return {'status': 0, 'statusMessage': "Successfully paused logging."}
    else:
        return {'status': 1, 'statusMessage': "Logging already paused or stopped."}
예제 #22
0
	def connect(self):
		"""	Connect to the socket represented by BrewPiSocket. Returns a new connected socket object.
		This function should be called when the socket is created by a different instance of brewpi.
		"""
		sock = socket.socket
		try:
			if self.type == 'i':  # Internet socket
				sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
				sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
				util.logMessage('Bound to existing TCP socket on port %d ' % self.port)
				sock.connect((self.host, self.port))
			else:
				sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
				sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
				sock.connect(self.file)
		except socket.error:
			sock = False
		finally:
			return sock
예제 #23
0
    def parseProcess(self, process):
        """
        Converts a psutil process into a BrewPiProcess object by parsing the config file it has been called with.
        Params: a psutil.Process object
        Returns: BrewPiProcess object
        """
        bp = BrewPiProcess()
        bp.pid = process._pid

        cfg = [s for s in process.cmdline() if '.cfg' in s]  # get config file argument
        if cfg:
            cfg = cfg[0]  # add full path to config file
        else:
            # use default config file location
            cfg = util.scriptPath() + "/settings/config.cfg"
        bp.cfg = util.readCfgWithDefaults(cfg)
        bp.port = bp.cfg['port']
        bp.sock = BrewPiSocket.BrewPiSocket(bp.cfg)
        return bp
예제 #24
0
def startBeer(beerName):
    global config
    global localJsonFileName
    global localCsvFileName
    global wwwJsonFileName
    global wwwCsvFileName
    global lastDay
    global day

    # create directory for the data if it does not exist
    dataPath = util.addSlash(config["scriptPath"]) + "data/" + beerName + "/"
    wwwDataPath = util.addSlash(config["wwwPath"]) + "data/" + beerName + "/"

    if not os.path.exists(dataPath):
        os.makedirs(dataPath)
        os.chmod(dataPath, 0775)  # give group all permissions
    if not os.path.exists(wwwDataPath):
        os.makedirs(wwwDataPath)
        os.chmod(wwwDataPath, 0775)  # sudgive group all permissions

        # Keep track of day and make new data tabe for each day
        # This limits data table size, which can grow very big otherwise
    day = time.strftime("%Y-%m-%d")
    lastDay = day
    # define a JSON file to store the data table
    jsonFileName = config["beerName"] + "-" + day
    # if a file for today already existed, add suffix
    if os.path.isfile(dataPath + jsonFileName + ".json"):
        i = 1
        while os.path.isfile(dataPath + jsonFileName + "-" + str(i) + ".json"):
            i += 1
        jsonFileName = jsonFileName + "-" + str(i)
    localJsonFileName = dataPath + jsonFileName + ".json"
    brewpiJson.newEmptyFile(localJsonFileName)

    # Define a location on the web server to copy the file to after it is written
    wwwJsonFileName = wwwDataPath + jsonFileName + ".json"

    # Define a CSV file to store the data as CSV (might be useful one day)
    localCsvFileName = dataPath + config["beerName"] + ".csv"
    wwwCsvFileName = wwwDataPath + config["beerName"] + ".csv"
    changeWwwSetting("beerName", beerName)
예제 #25
0
def getNewTemp(scriptPath):
    temperatureReader = csv.reader(	open(util.addSlash(scriptPath) + 'settings/tempProfile.csv', 'rb'),
                                    delimiter=',', quoting=csv.QUOTE_ALL)
    temperatureReader.next()  # discard the first row, which is the table header
    prevTemp = None
    nextTemp = None
    interpolatedTemp = -99
    prevDate = None
    nextDate = None


    now = time.mktime(time.localtime())  # get current time in seconds since epoch

    for row in temperatureReader:
        dateString = row[0]
        try:
            date = time.mktime(time.strptime(dateString, "%Y-%m-%dT%H:%M:%S"))
        except ValueError:
            continue  # skip dates that cannot be parsed

        try:
            temperature = float(row[1])
        except ValueError:
            if row[1].strip() == '':
                # cell is left empty, this is allowed to disable temperature control in part of the profile
                temperature = None
            else:
                # invalid number string, skip this row
                continue

        prevTemp = nextTemp
        nextTemp = temperature
        prevDate = nextDate
        nextDate = date
        timeDiff = now - nextDate
        if timeDiff < 0:
            if prevDate is None:
                interpolatedTemp = nextTemp  # first set point is in the future
                break
            else:
                if prevTemp is None or nextTemp is None:
                    # When the previous or next temperature is an empty cell, disable temperature control.
                    # This is useful to stop temperature control after a while or to not start right away.
                    interpolatedTemp = None
                else:
                    interpolatedTemp = ((now - prevDate) / (nextDate - prevDate) * (nextTemp - prevTemp) + prevTemp)
                    interpolatedTemp = round(interpolatedTemp, 2)
                break

    if interpolatedTemp == -99:  # all set points in the past
        interpolatedTemp = nextTemp

    return interpolatedTemp
예제 #26
0
 def read(self, size=1):
     #Returns:    Bytes read from the port.
     #Read size bytes from the serial port. If a timeout is set it may return less characters as requested. With no timeout it will block until the requested number of bytes is read.
     bytes=None
     try: 
         bytes=self.sock.recv(size)
     except socket.timeout: # timeout on receive just means there is nothing in the buffer.  This is not an error
         return None
     except socket.error: # other socket errors probably mean we lost our connection.  try to recover it.
         if self.retryCount < self.retries:
             self.retryCount=self.retryCount+1
             BrewPiUtil.logMessage("Lost connection to controller on read. Attempting to reconnect.")
             self.sock.close()
             self.open()
             bytes=self.read(size)
         else:
             self.sock.close()
             BrewPiUtil.logMessage("Lost connection to controller on read. Exiting.")
             sys.exit(1)
             # return None
     if bytes is not None:
         if self.retryCount > 0:
             BrewPiUtil.logMessage("Successfully reconnected to controller on read.")
             self.retryCount = 0
     return bytes
예제 #27
0
def detect_port(bootLoader=False, my_port=None):
    """
    :return: first detected serial port as tuple: (port, name)
    :rtype:
    """
    if my_port == "auto":
        my_port = None

    port = (None, None)
    ports = find_compatible_serial_ports(bootLoader=bootLoader,
                                         my_port=my_port)

    try:
        port = next(ports)
    except StopIteration:
        return port
    try:
        another_port = next(ports)
        BrewPiUtil.logMessage("Warning: Multiple compatible ports.")
    except StopIteration:
        pass
    return port
    def save_settings_to_file(self):
        oldSettingsFileName = 'settings-' + time.strftime("%b-%d-%Y-%H-%M-%S") + '.json'
        settingsBackupDir = util.scriptPath() + '/settings/controller-backup/'
        if not os.path.exists(settingsBackupDir):
            os.makedirs(settingsBackupDir, 0777)

        oldSettingsFilePath = os.path.join(settingsBackupDir, oldSettingsFileName)
        oldSettingsFile = open(oldSettingsFilePath, 'wb')
        oldSettingsFile.write(json.dumps(self.oldSettings))
        oldSettingsFile.truncate()
        oldSettingsFile.close()
        os.chmod(oldSettingsFilePath, 0777) # make sure file can be accessed by all in case the script ran as root
        printStdErr("Saved old settings to file " + oldSettingsFileName)
예제 #29
0
    def save_settings_to_file(self):
        oldSettingsFileName = 'settings-' + time.strftime("%b-%d-%Y-%H-%M-%S") + '.json'
        settingsBackupDir = util.scriptPath() + '/settings/controller-backup/'
        if not os.path.exists(settingsBackupDir):
            os.makedirs(settingsBackupDir, 0777)

        oldSettingsFilePath = os.path.join(settingsBackupDir, oldSettingsFileName)
        oldSettingsFile = open(oldSettingsFilePath, 'wb')
        oldSettingsFile.write(json.dumps(self.oldSettings))
        oldSettingsFile.truncate()
        oldSettingsFile.close()
        os.chmod(oldSettingsFilePath, 0777) # make sure file can be accessed by all in case the script ran as root
        printStdErr("Saved old settings to file " + oldSettingsFileName)
예제 #30
0
 def parseProcess(self, process):
     """
     Converts a psutil process into a BrewPiProcess object by parsing the config file it has been called with.
     Params: a psutil.Process object
     Returns: BrewPiProcess object
     """
     bp = BrewPiProcess()
     try:
         bp.pid = process._pid
         cfg = [s for s in process.cmdline()
                if '.cfg' in s]  # get config file argument
     except psutil.NoSuchProcess:
         # process no longer exists
         return None
     if cfg:
         cfg = cfg[0]  # add full path to config file
     else:
         # use default config file location
         cfg = util.scriptPath() + "/settings/config.cfg"
     bp.cfg = util.readCfgWithDefaults(cfg)
     bp.port = bp.cfg['port']
     bp.sock = BrewPiSocket.BrewPiSocket(bp.cfg)
     return bp
예제 #31
0
 def write(self, data):
     #Returns:    Number of bytes written.
     #Raises SerialTimeoutException:
     #     In case a write timeout is configured for the port and the time is exceeded.
     #Write the string data to the port.
     try:
         bytes=self.sock.sendall(data)
     except socket.timeout: # A write timeout is probably a connection issue
         if self.retryCount < self.retries:
             self.retryCount=self.retryCount+1
             BrewPiUtil.logMessage("Lost connection to controller on write. Attempting to reconnect.")
             self.sock.close()
             self.open()
             bytes=self.write(data)
         else:
             self.sock.close()
             BrewPiUtil.logMessage("Lost connection to controller on write. Exiting.")
             sys.exit(1)
             # return -1
     except socket.error: # general errors are most likely to be a timeout disconnect from BrewPi, so try to recover.
         if self.retryCount < self.retries:
             BrewPiUtil.logMessage("Lost connection to controller on write. Attempting to reconnect.")
             self.retryCount=self.retryCount+1
             self.sock.close()
             self.open()
             bytes=self.write(data)
         else:
             self.sock.close()
             BrewPiUtil.logMessage("Lost connection to controller on write, with socket.error. Exiting.")
             sys.exit(1)
             # return -1
     if bytes>=0:
         if self.retryCount > 0:
             BrewPiUtil.logMessage("Successfully reconnected to controller on write.")
             self.retryCount = 0
     return bytes
예제 #32
0
    def parseProcess(self, process):
        """
        Converts a psutil process into a BrewPiProcess object by parsing the config file it has been called with.
        Params: a psutil.Process object
        Returns: BrewPiProcess object
        """
        bp = BrewPiProcess()
        bp.pid = process._pid

        cfg = [s for s in process.cmdline
               if '.cfg' in s]  # get config file argument
        if cfg:
            cfg = cfg[0]  # add full path to config file
        bp.cfg = util.readCfgWithDefaults(cfg)

        bp.port = bp.cfg['port']
        bp.sock = BrewPiSocket.BrewPiSocket(bp.cfg)
        return bp
예제 #33
0
def changeWwwSetting(settingName, value):
    wwwSettingsFileName = util.addSlash(config['wwwPath']) + 'userSettings.json'
    if os.path.exists(wwwSettingsFileName):
        wwwSettingsFile = open(wwwSettingsFileName, 'r+b')
        try:
            wwwSettings = json.load(wwwSettingsFile)  # read existing settings
        except json.JSONDecodeError:
            logMessage("Error in decoding userSettings.json, creating new empty json file")
            wwwSettings = {}  # start with a fresh file when the json is corrupt.
    else:
        wwwSettingsFile = open(wwwSettingsFileName, 'w+b')  # create new file
        wwwSettings = {}

    wwwSettings[settingName] = str(value)
    wwwSettingsFile.seek(0)
    wwwSettingsFile.write(json.dumps(wwwSettings))
    wwwSettingsFile.truncate()
    wwwSettingsFile.close()
예제 #34
0
def changeWwwSetting(settingName, value):
    wwwSettingsFileName = util.addSlash(config['wwwPath']) + 'userSettings.json'
    if os.path.exists(wwwSettingsFileName):
        wwwSettingsFile = open(wwwSettingsFileName, 'r+b')
        try:
            wwwSettings = json.load(wwwSettingsFile)  # read existing settings
        except json.JSONDecodeError:
            logMessage("Error in decoding userSettings.json, creating new empty json file")
            wwwSettings = {}  # start with a fresh file when the json is corrupt.
    else:
        wwwSettingsFile = open(wwwSettingsFileName, 'w+b')  # create new file
        wwwSettings = {}

    wwwSettings[settingName] = str(value)
    wwwSettingsFile.seek(0)
    wwwSettingsFile.write(json.dumps(wwwSettings))
    wwwSettingsFile.truncate()
    wwwSettingsFile.close()
예제 #35
0
 def open(self):
     mdnsLocator.locate_brewpi_services()  # This causes all the BrewPi devices to resend their mDNS info
     try:
         self.sock.connect((self.host, self.port))
         BrewPiUtil.logMessage("Successfully connected to controller.")
     except socket.gaierror as e:
         BrewPiUtil.logMessage("Unable to connect to BrewPi " + self.host + " on port " + str(self.port) +
                               ". Exiting.")
         sys.exit(1)
     except socket.error as e:  # Catches "bad file descriptor" error
         BrewPiUtil.logMessage("Unable to connect to BrewPi " + self.host + " on port " + str(self.port) +
                               ". Exiting.")
         sys.exit(1)
예제 #36
0
	def __init__(self, cfg):
		""" Creates a BrewPi socket object and reads the settings from a BrewPi ConfigObj.
		Does not create a socket, just prepares the settings.

		Args:
		cfg: a ConfigObj object form a BrewPi config file
		"""

		self.type = 'f'  # default to file socket
		self.file = None
		self.host = 'localhost'
		self.port = None
		self.sock = 0

		isWindows = sys.platform.startswith('win')
		useInternetSocket = bool(cfg.get('useInternetSocket', isWindows))
		if useInternetSocket:
			self.port = cfg.get('socketPort', 6332)
			self.type = 'i'
		else:
			self.file = util.addSlash(cfg['scriptPath']) + 'BEERSOCKET'
예제 #37
0
def lineFromSerial(ser):
    global serialBuffer
    inWaiting = None
    newData = None
    try:
        inWaiting = ser.inWaiting()
        if inWaiting > 0:
            newData = ser.read(inWaiting)
    except (IOError, OSError, SerialException) as e:
        logMessage('Serial Error: {0})'.format(str(e)))
        return
    if newData:
        serialBuffer = serialBuffer + newData
    if '\n' in serialBuffer:
        lines = serialBuffer.partition('\n') # returns 3-tuple with line, separator, rest
        if(lines[1] == ''):
            # '\n' not found, first element is incomplete line
            serialBuffer = lines[0]
            return None
        else:
            # complete line received, [0] is complete line [1] is separator [2] is the rest
            serialBuffer = lines[2]
            return util.asciiToUnicode(lines[0])
예제 #38
0
def lineFromSerial(ser):
    global serialBuffer
    inWaiting = None
    newData = None
    try:
        inWaiting = ser.inWaiting()
        if inWaiting > 0:
            newData = ser.read(inWaiting)
    except (IOError, OSError, SerialException) as e:
        logMessage('Serial Error: {0})'.format(str(e)))
        return
    if newData:
        serialBuffer = serialBuffer + newData
    if '\n' in serialBuffer:
        lines = serialBuffer.partition('\n') # returns 3-tuple with line, separator, rest
        if(lines[1] == ''):
            # '\n' not found, first element is incomplete line
            serialBuffer = lines[0]
            return None
        else:
            # complete line received, [0] is complete line [1] is separator [2] is the rest
            serialBuffer = lines[2]
            return util.asciiToUnicode(lines[0])
예제 #39
0
    def save_settings(self):
        ser, oldSettings = self.ser, self.oldSettings
        oldSettings.clear()
        printStdErr("Requesting old settings from %(a)s..." % msg_map)
        expected_responses = 2
        if self.avrVersionOld.minor > 1:  # older versions did not have a device manager
            expected_responses += 1
            ser.write("d{}")  # installed devices
            time.sleep(1)
        ser.write("c")  # control constants
        ser.write("s")  # control settings
        time.sleep(2)

        while expected_responses:
            line = ser.readline()
            if line:
                if line[0] == 'C':
                    expected_responses -= 1
                    oldSettings['controlConstants'] = json_decode_response(line)
                elif line[0] == 'S':
                    expected_responses -= 1
                    oldSettings['controlSettings'] = json_decode_response(line)
                elif line[0] == 'd':
                    expected_responses -= 1
                    oldSettings['installedDevices'] = json_decode_response(line)

        oldSettingsFileName = 'oldAvrSettings-' + time.strftime("%b-%d-%Y-%H-%M-%S") + '.json'

        scriptDir = util.scriptPath()  # <-- absolute dir the script is in
        if not os.path.exists(scriptDir + '/settings/avr-backup/'):
            os.makedirs(scriptDir + '/settings/avr-backup/')

        oldSettingsFile = open(scriptDir + '/settings/avr-backup/' + oldSettingsFileName, 'wb')
        oldSettingsFile.write(json.dumps(oldSettings))
        oldSettingsFile.truncate()
        oldSettingsFile.close()
        printStdErr("Saved old settings to file " + oldSettingsFileName)
예제 #40
0
def updateFromGitHub(userInput = False, restoreSettings = True, restoreDevices = True):
    import BrewPiUtil as util
    from gitHubReleases import gitHubReleases
    import brewpiVersion
    import programController as programmer

    configFile = util.scriptPath() + '/settings/config.cfg'
    config = util.readCfgWithDefaults(configFile)

    printStdErr("Stopping any running instances of BrewPi to check/update controller...")
    quitBrewPi(config['wwwPath'])

    hwVersion = None
    shield = None
    board = None
    boardName = None
    family = None
    ser = None

    ### Get version number
    printStdErr("\nChecking current firmware version...")
    try:
        ser = util.setupSerial(config)
        hwVersion = brewpiVersion.getVersionFromSerial(ser)
        family = hwVersion.family
        shield = hwVersion.shield
        board = hwVersion.board
        boardName = hwVersion.boardName()
    except:
        printStdErr("Unable to connect to controller, perhaps it is disconnected or otherwise unavailable.")
        return -1

    if ser:
        ser.close()  # close serial port
        ser = None

    if not hwVersion:
        printStdErr("Unable to retrieve firmware version from controller")
        printStdErr("If your controller has not been programmed with an earlier version of BrewPi,"
                    " follow these instructions:")
        printStdErr("\n If you have an Arduino:")
        printStdErr("Please go to https://github.com/BrewPi/firmware/releases to download"
                    "the firmware and upload via the BrewPi web interface")
        printStdErr("\n If you have a Spark Core:")
        printStdErr("Put it in DFU mode and run: sudo /home/brewpi/utils/flashDfu.py")
    else:
        printStdErr("Current firmware version on controller: " + hwVersion.toString())

    printStdErr("\nChecking GitHub for latest release...")
    releases = gitHubReleases("https://api.github.com/repos/BrewPi/firmware")
    latest = releases.getLatestTag()
    printStdErr("Latest version on GitHub: " + latest)
    if hwVersion.isNewer(latest):
        printStdErr("\nVersion on GitHub is newer than your current version, downloading new version...")
    else:

        printStdErr("\nYour current firmware version is up-to-date. There is no need to update.")
        if userInput:
            printStdErr("If you are encountering problems, you can reprogram anyway."
                        " Would you like to do this?"
                        "\nType yes to reprogram or just press enter to keep your current firmware: ")
            choice = raw_input()
            if not any(choice == x for x in ["yes", "Yes", "YES", "yes", "y", "Y"]):
                return 0
            printStdErr("Would you like me to try to restore you settings after programming? [Y/n]: ")
            choice = raw_input()
            if not any(choice == x for x in ["", "yes", "Yes", "YES", "yes", "y", "Y"]):
                restoreSettings = False
            printStdErr("Would you like me to try to restore your configured devices after programming? [Y/n]: ")
            choice = raw_input()
            if not any(choice == x for x in ["", "yes", "Yes", "YES", "yes", "y", "Y"]):
                restoreDevices = False
        else:
            return 0

    printStdErr("Downloading latest firmware...")
    localFileName = None
    if family == "Arduino":
        localFileName = releases.getBin(latest, [boardName, shield, ".hex"])
    elif family == "Spark":
        localFileName = releases.getBin(latest, [boardName, ".bin"])

    if localFileName:
        printStdErr("Latest firmware downloaded to " + localFileName)
    else:
        printStdErr("Downloading firmware failed")
        return -1

    result = programmer.programController(config, board, localFileName,
                                          {'settings': restoreSettings, 'devices': restoreDevices})
    util.removeDontRunFile(config['wwwPath'] + "/do_not_run_brewpi")
    return result
예제 #41
0
# along with BrewPi.  If not, see <http://www.gnu.org/licenses/>.

import msvcrt
import sys
import os
import simplejson as json

# append parent directory to be able to import files
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/..")
import expandLogMessage
import BrewPiUtil as util

# Read in command line arguments
if len(sys.argv) < 2:
    print >> sys.stderr, 'Using default config path ./settings/config.cfg, to override use : %s <config file full path>' % sys.argv[0]
    configFile = util.addSlash(sys.path[0]) + '../settings/config.cfg'
else:
    configFile = sys.argv[1]

if not os.path.exists(configFile):
    sys.exit('ERROR: Config file "%s" was not found!' % configFile)

config = util.readCfgWithDefaults(configFile)

print "***** BrewPi Windows Test Terminal ****"
print "This simple Python script lets you send commands to the Arduino."
print "It also echoes everything the Arduino returns."
print "On known debug ID's in JSON format, it expands the messages to the full message"
print "press 's' to send a string to the Arduino, press 'q' to quit"

# open serial port
예제 #42
0
choice = raw_input("\nThe update script can automatically check your Arduino version and " +
                   "program it with the latest hex file from the BrewPi server, would you like to do this now? [Y/n]:")
if (choice is "") or (choice is "Y") or (choice is "y") or (choice is "yes") or (choice is "YES"):
    print "Stopping any running instances of BrewPi to check/update hex file..."
    quitBrewPi(webPath)

    ### Check arduino hex file version against current brewpi version
    print "\nChecking Arduino hex file version..."
    try:
        import BrewPiUtil as util
    except:
        print "Error reading config util path"

    configFile = scriptPath + '/settings/config.cfg'
    config = util.readCfgWithDefaults(configFile)

    ### Get version number
    try:
        import brewpiVersion
        ser, conn = util.setupSerial(config)
        hwVersion = brewpiVersion.getVersionFromSerial(ser)
        shield = hwVersion.shield
        board = hwVersion.board
        if "standard" in board:
            board = "uno"
        with open(scriptPath + '/brewpi.py', 'r') as versionFile:
            for line in versionFile:
                if 'compatibleHwVersion =' in line:
                    bpVersion = line.split("= ")[1].replace("\"", "")
                    break
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with BrewPi.  If not, see <http://www.gnu.org/licenses/>.

import os
import sys
from configobj import ConfigObj

import programArduino as programmer
import BrewPiUtil as util

# Read in command line arguments
if len(sys.argv) < 2:
	sys.exit('Usage: %s <config file full path>' % sys.argv[0])
if not os.path.exists(sys.argv[1]):
	sys.exit('ERROR: Config file "%s" was not found!' % sys.argv[1])

configFile = sys.argv[1]
config = ConfigObj(configFile)

# global variables, will be initialized by startBeer()
util.readCfgWithDefaults(configFile)

hexFile = config['wwwPath'] + 'uploads/brewpi-uno-revC.hex'
boardType = config['boardType']

result = programmer.programArduino(config, boardType, hexFile, {'settings': True, 'devices': True})

print result
예제 #44
0
def updateFromGitHub(userInput, beta, useDfu, restoreSettings=True, restoreDevices=True):
    import BrewPiUtil as util
    from gitHubReleases import gitHubReleases
    import brewpiVersion
    import programController as programmer

    configFile = util.scriptPath() + "/settings/config.cfg"
    config = util.readCfgWithDefaults(configFile)

    printStdErr("Stopping any running instances of BrewPi to check/update controller...")
    quitBrewPi(config["wwwPath"])

    hwVersion = None
    shield = None
    board = None
    family = None
    ser = None

    ### Get version number
    printStdErr("\nChecking current firmware version...")
    try:
        ser = util.setupSerial(config)
        hwVersion = brewpiVersion.getVersionFromSerial(ser)
        family = hwVersion.family
        shield = hwVersion.shield
        board = hwVersion.board

        printStdErr("Found " + hwVersion.toExtendedString() + " on port " + ser.name + "\n")
    except:
        if hwVersion is None:
            printStdErr(
                "Unable to receive version from controller.\n"
                "Is your controller unresponsive and do you wish to try restoring your firmware? [y/N]: "
            )
            choice = raw_input()
            if not any(choice == x for x in ["yes", "Yes", "YES", "yes", "y", "Y"]):
                printStdErr("Please make sure your controller is connected properly and try again.")
                return 0
            port, name = autoSerial.detect_port()
            if not port:
                printStdErr("Could not find compatible device in available serial ports.")
                return 0
            if "Particle" in name:
                family = "Particle"
                if "Photon" in name:
                    board = "photon"
                elif "Core" in name:
                    board = "core"
            elif "Arduino" in name:
                family = "Arduino"
                if "Leonardo" in name:
                    board = "leonardo"
                elif "Uno" in name:
                    board = "uno"

            if board is None:
                printStdErr("Unable to connect to controller, perhaps it is disconnected or otherwise unavailable.")
                return -1
            else:
                printStdErr("Will try to restore the firmware on your %s" % name)
                if family == "Arduino":
                    printStdErr(
                        "Assuming a Rev C shield. If this is not the case, please program your Arduino manually"
                    )
                    shield = "RevC"
                else:
                    printStdErr(
                        "Please put your controller in DFU mode now by holding the setup button during reset, until the LED blinks yellow."
                    )
                    printStdErr("Press Enter when ready.")
                    choice = raw_input()
                    useDfu = True  # use dfu mode when board is not responding to serial

    if ser:
        ser.close()  # close serial port
        ser = None

    if hwVersion:
        printStdErr("Current firmware version on controller: " + hwVersion.toString())
    else:
        restoreDevices = False
        restoreSettings = False

    printStdErr("\nChecking GitHub for available release...")
    releases = gitHubReleases("https://api.github.com/repos/BrewPi/firmware")

    availableTags = releases.getTags(beta)
    stableTags = releases.getTags(False)
    compatibleTags = []
    for tag in availableTags:
        url = None
        if family == "Arduino":
            url = releases.getBinUrl(tag, [board, shield, ".hex"])
        elif family == "Spark" or family == "Particle":
            url = releases.getBinUrl(tag, [board, "brewpi", ".bin"])
        if url is not None:
            compatibleTags.append(tag)

    if len(compatibleTags) == 0:
        printStdErr("No compatible releases found for %s %s" % (family, board))
        return -1

    # default tag is latest stable tag, or latest unstable tag if no stable tag is found
    default_choice = next((i for i, t in enumerate(compatibleTags) if t in stableTags), compatibleTags[0])
    tag = compatibleTags[default_choice]

    if userInput:
        print("\nAvailable releases:\n")
        for i, menu_tag in enumerate(compatibleTags):
            print("[%d] %s" % (i, menu_tag))
        print("[" + str(len(compatibleTags)) + "] Cancel firmware update")
        num_choices = len(compatibleTags)
        while 1:
            try:
                choice = raw_input(
                    "Enter the number [0-%d] of the version you want to program [default = %d (%s)]: "
                    % (num_choices, default_choice, tag)
                )
                if choice == "":
                    break
                else:
                    selection = int(choice)
            except ValueError:
                print("Use the number! [0-%d]" % num_choices)
                continue
            if selection == num_choices:
                return False  # choice = skip updating
            try:
                tag = compatibleTags[selection]
            except IndexError:
                print("Not a valid choice. Try again")
                continue
            break
    else:
        printStdErr("Latest version on GitHub: " + tag)

    if hwVersion is not None and not hwVersion.isNewer(tag):
        if hwVersion.isEqual(tag):
            printStdErr("You are already running version %s." % tag)
        else:
            printStdErr("Your current version is newer than %s." % tag)

        if userInput:
            printStdErr(
                "If you are encountering problems, you can reprogram anyway."
                " Would you like to do this?"
                "\nType yes to reprogram or just press enter to keep your current firmware: "
            )
            choice = raw_input()
            if not any(choice == x for x in ["yes", "Yes", "YES", "yes", "y", "Y"]):
                return 0
        else:
            printStdErr("No update needed. Exiting.")
            exit(0)

    if hwVersion is not None and userInput:
        printStdErr("Would you like me to try to restore you settings after programming? [Y/n]: ")
        choice = raw_input()
        if not any(choice == x for x in ["", "yes", "Yes", "YES", "yes", "y", "Y"]):
            restoreSettings = False
        printStdErr("Would you like me to try to restore your configured devices after programming? [Y/n]: ")
        choice = raw_input()
        if not any(choice == x for x in ["", "yes", "Yes", "YES", "yes", "y", "Y"]):
            restoreDevices = False

    printStdErr("Downloading firmware...")
    localFileName = None
    system1 = None
    system2 = None

    if family == "Arduino":
        localFileName = releases.getBin(tag, [board, shield, ".hex"])
    elif family == "Spark" or family == "Particle":
        localFileName = releases.getBin(tag, [board, "brewpi", ".bin"])
    else:
        printStdErr("Error: Device family {0} not recognized".format(family))
        return -1

    if board == "photon":
        if hwVersion:
            oldVersion = hwVersion.version.vstring
        else:
            oldVersion = "0.0.0"
        latestSystemTag = releases.getLatestTagForSystem(prerelease=beta, since=oldVersion)
        if latestSystemTag is not None:
            printStdErr("Updated system firmware for the photon found in release {0}".format(latestSystemTag))
            system1 = releases.getBin(latestSystemTag, ["photon", "system-part1", ".bin"])
            system2 = releases.getBin(latestSystemTag, ["photon", "system-part2", ".bin"])
            if system1:
                printStdErr("Downloaded new system firmware to:\n")
                printStdErr("{0}\nand\n".format(system1))
                if system2:
                    printStdErr("{0}\n".format(system2))
                else:
                    printStdErr("Error: system firmware part2 not found in release")
                    return -1
        else:
            printStdErr("Photon system firmware is up to date.\n")

    if localFileName:
        printStdErr("Latest firmware downloaded to:\n" + localFileName)
    else:
        printStdErr("Downloading firmware failed")
        return -1

    printStdErr("\nUpdating firmware...\n")
    result = programmer.programController(
        config, board, localFileName, system1, system2, useDfu, {"settings": restoreSettings, "devices": restoreDevices}
    )
    util.removeDontRunFile(config["wwwPath"] + "/do_not_run_brewpi")
    return result
예제 #45
0
                    print "Updating system firmware for the {0}, part 2: {1}".format(device_type, system2)
                    p = subprocess.Popen(dfuPath + " -d {0} -a 0 -s 0x8060000 -D {1}".format(pid_vid[device_type], system2), shell=True)
                    p.wait()
                    time.sleep(1)

                print "Now writing BrewPi firmware {0} to {1}".format(binFile, device_type)
                p = subprocess.Popen(dfuPath + " -d {0} -a 0 -s 0x80A0000:leave -D {1}".format(pid_vid[device_type], binFile), shell=True)
                p.wait()
                time.sleep(1)

            print "Programming done"

            if not noReset:
                print "Now resetting EEPROM to defaults"
                # reset EEPROM to defaults
                configFile = util.scriptPath() + '/settings/config.cfg'
                config = util.readCfgWithDefaults(configFile)
                config_copy = config
                if 'socket:' in config['port']:
                    print "Socket configured as serial port, using auto detect to find USB serial"
                    config_copy['port'] = 'auto'

                raw_input("Press Enter to continue...")

                programmer = SerialProgrammer.create(config_copy, device_type)
                # open serial port
                print "Opening serial port to reset factory defaults"
                if not programmer.open_serial_with_retry(config_copy, 57600, 1):
                    print "Could not open serial port after programming"
                else:
                    programmer.fetch_version("Success! ")
예제 #46
0
        if len(allProcesses.update()) > 1:  # if I am not the only one running
            allProcesses.quitAll()
            time.sleep(2)
            if len(allProcesses.update()) > 1:
                print "Asking the other processes to quit nicely did not work. Killing them with force!"
    # redirect output of stderr and stdout to files in log directory
    if o in ('-l', '--log'):
        logToFiles = True
    # only start brewpi when the dontrunfile is not found
    if o in ('-d', '--dontrunfile'):
        checkDontRunFile = True
    if o in ('--checkstartuponly'):
        checkStartupOnly = True

if not configFile:
    configFile = util.addSlash(sys.path[0]) + 'settings/config.cfg'

config = util.readCfgWithDefaults(configFile)

dontRunFilePath = config['wwwPath'] + 'do_not_run_brewpi'
# check dont run file when it exists and exit it it does
if checkDontRunFile:
    if os.path.exists(dontRunFilePath):
        # do not print anything, this will flood the logs
        exit(0)

# check for other running instances of BrewPi that will cause conflicts with this instance
allProcesses = BrewPiProcess.BrewPiProcesses()
allProcesses.update()
myProcess = allProcesses.me()
if allProcesses.findConflicts(myProcess):
예제 #47
0
        if len(allProcesses.update()) > 1:  # if I am not the only one running
            allProcesses.quitAll()
            time.sleep(2)
            if len(allProcesses.update()) > 1:
                printStdErr("Asking the other processes to quit nicely did not work. Killing them with force!")
    # redirect output of stderr and stdout to files in log directory
    if o in ('-l', '--log'):
        logToFiles = True
    # only start brewpi when the dontrunfile is not found
    if o in ('-d', '--dontrunfile'):
        checkDontRunFile = True
    if o in ('--checkstartuponly'):
        checkStartupOnly = True

if not configFile:
    configFile = util.addSlash(sys.path[0]) + 'settings/config.cfg'

config = util.readCfgWithDefaults(configFile)

dontRunFilePath = os.path.join(config['wwwPath'], 'do_not_run_brewpi')
# check dont run file when it exists and exit it it does
if checkDontRunFile:
    if os.path.exists(dontRunFilePath):
        # do not print anything, this will flood the logs
        exit(0)

# check for other running instances of BrewPi that will cause conflicts with this instance
allProcesses = BrewPiProcess.BrewPiProcesses()
allProcesses.update()
myProcess = allProcesses.me()
if allProcesses.findConflicts(myProcess):
예제 #48
0
import msvcrt
import sys
import os
# import simplejson as json
import json

# append parent directory to be able to import files
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/..")
import expandLogMessage
import BrewPiUtil as util

# Read in command line arguments
if len(sys.argv) < 2:
    print >> sys.stderr, 'Using default config path ./settings/config.cfg, to override use : %s <config file full path>' % sys.argv[
        0]
    configFile = util.addSlash(sys.path[0]) + '../settings/config.cfg'
else:
    configFile = sys.argv[1]

if not os.path.exists(configFile):
    sys.exit('ERROR: Config file "%s" was not found!' % configFile)

config = util.readCfgWithDefaults(configFile)

print "***** BrewPi Windows Test Terminal ****"
print "This simple Python script lets you send commands to the Arduino."
print "It also echoes everything the Arduino returns."
print "On known debug ID's in JSON format, it expands the messages to the full message"
print "press 's' to send a string to the Arduino, press 'q' to quit"

# open serial port
예제 #49
0
            time.sleep(2)
            if len(allProcesses.update()) > 1:
                printStdErr(
                    "Asking the other processes to quit nicely did not work. Killing them with force!"
                )
    # redirect output of stderr and stdout to files in log directory
    if o in ('-l', '--log'):
        logToFiles = True
    # only start brewpi when the dontrunfile is not found
    if o in ('-d', '--dontrunfile'):
        checkDontRunFile = True
    if o in ('--checkstartuponly'):
        checkStartupOnly = True

if not configFile:
    configFile = util.addSlash(sys.path[0]) + 'settings/config.cfg'

config = util.readCfgWithDefaults(configFile)

dontRunFilePath = os.path.join(config['wwwPath'], 'do_not_run_brewpi')
# check dont run file when it exists and exit it it does
if checkDontRunFile:
    if os.path.exists(dontRunFilePath):
        # do not print anything, this will flood the logs
        exit(0)

# check for other running instances of BrewPi that will cause conflicts with this instance
allProcesses = BrewPiProcess.BrewPiProcesses()
allProcesses.update()
myProcess = allProcesses.me()
if allProcesses.findConflicts(myProcess):
예제 #50
0
                # complete line received, [0] is complete line [1] is separator [2] is the rest
                self.buffer = lines[2]
                return self.__asciiToUnicode(lines[0])

    # remove extended ascii characters from string, because they can raise UnicodeDecodeError later
    def __asciiToUnicode(self, s):
        s = s.replace(chr(0xB0), '&deg')
        return unicode(s, 'ascii', 'ignore')

if __name__ == '__main__':
    # some test code that requests data from serial and processes the response json
    import simplejson
    import time
    import BrewPiUtil as util

    config_file = util.addSlash(sys.path[0]) + 'settings/config.cfg'
    config = util.readCfgWithDefaults(config_file)
    ser = util.setupSerial(config, time_out=0)
    if not ser:
        printStdErr("Could not open Serial Port")
        exit()

    bg_ser = BackGroundSerial(ser)
    bg_ser.start()

    success = 0
    fail = 0
    for i in range(1, 5):
        # request control variables 4 times. This would overrun buffer if it was not read in a background thread
        # the json decode will then fail, because the message is clipped
        bg_ser.write('v')
예제 #51
0
# You should have received a copy of the GNU General Public License
# along with BrewPi.  If not, see <http://www.gnu.org/licenses/>.

import serial
import msvcrt
import sys
import os
import simplejson as json
import expandLogMessage
import BrewPiUtil as util

# Read in command line arguments
if len(sys.argv) < 2:
    print >> sys.stderr, 'Using default config path ./settings/config.cfg, to override use : %s <config file full path>' % sys.argv[0]
    configFile = util.addSlash(sys.path[0]) + 'settings/config.cfg'
else:
    configFile = sys.argv[1]

if not os.path.exists(configFile):
    sys.exit('ERROR: Config file "%s" was not found!' % configFile)

config = util.readCfgWithDefaults(configFile)

print "***** BrewPi Windows Test Terminal ****"
print "This simple Python script lets you send commands to the Arduino."
print "It also echoes everything the Arduino returns."
print "On known debug ID's in JSON format, it expands the messages to the full message"
print "press 's' to send a string to the Arduino, press 'q' to quit"

ser = 0
예제 #52
0
    def flash_file(self, hexFile):
        config, boardType = self.config, self.boardType
        printStdErr("\nLoading programming settings from board.txt.")
        # location of Arduino sdk
        arduinohome = config.get('arduinoHome', '/usr/share/arduino/')
        # location of avr tools
        avrdudehome = config.get(
            'avrdudeHome', arduinohome + 'hardware/tools/')
        # default to empty string because avrsize is on path
        avrsizehome = config.get('avrsizeHome', '')

        # location of global avr conf
        avrconf = config.get('avrConf', avrdudehome + 'avrdude.conf')

        boardsFile = loadBoardsFile(arduinohome)
        if not boardsFile:
            return False
        boardSettings = fetchBoardSettings(boardsFile, boardType)

        # parse the Arduino board file to get the right program settings
        for line in boardsFile:
            line = line.decode()
            if line.startswith(boardType):
                # strip board name, period and \n
                _boardType = (boardType + '.').encode()
                setting = line.encode().replace(_boardType, ''.encode(), 1).strip()
                [key, sign, val] = setting.rpartition('='.encode())
                boardSettings[key] = val

        printStdErr("\nChecking hex file size with avr-size.")

        # start programming the Arduino
        avrsizeCommand = avrsizehome + 'avr-size ' + "\"" + hexFile + "\""

        # check program size against maximum size
        p = sub.Popen(avrsizeCommand, stdout=sub.PIPE,
                      stderr=sub.PIPE, shell=True)
        output, errors = p.communicate()
        #if errors != "":
        #    printStdErr('\navr-size error: {0}'.format(errors))
        #    return False

        programSize = output.split()[7]
        printStdErr('\nProgram size: {0} bytes out of max {1}.'.format(programSize.decode(), boardSettings['upload.maximum_size']))

        # Another check just to be sure!
        if int(programSize.decode()) > int(boardSettings['upload.maximum_size']):
            printStdErr(
                "\nERROR: Program size is bigger than maximum size for your Arduino {0}.".format(boardType))
            return False

        hexFileDir = os.path.dirname(hexFile)
        hexFileLocal = os.path.basename(hexFile)

        time.sleep(1)
        # Get serial port while in bootloader
        bootLoaderPort = util.findSerialPort(bootLoader=True, my_port=config['port'])
        # bootLoaderPort = util.findSerialPort(bootLoader=True)
        if not bootLoaderPort:
            printStdErr("\nERROR: Could not find port in bootloader.")

        programCommand = (avrdudehome + 'avrdude' +
                          ' -F' +  # override device signature check
                          ' -e' +  # erase flash and eeprom before programming. This prevents issues with corrupted EEPROM
                          ' -p ' + boardSettings['build.mcu'] +
                          ' -c ' + boardSettings['upload.protocol'] +
                          ' -b ' + boardSettings['upload.speed'] +
                          ' -P ' + bootLoaderPort +
                          ' -U ' + 'flash:w:' + "\"" + hexFileLocal + "\"" +
                          ' -C ' + avrconf)

        printStdErr("\nProgramming Arduino with avrdude.")

        p = sub.Popen(programCommand, stdout=sub.PIPE,
                      stderr=sub.PIPE, shell=True, cwd=hexFileDir)
        output, errors = p.communicate()
        output = output.decode()
        errors = errors.decode()

        # avrdude only uses stderr, append its output to the returnString
        printStdErr("\nResult of invoking avrdude:{0}".format(errors))

        if("bytes of flash verified" in errors):
            printStdErr("Avrdude done, programming successful.")
        else:
            printStdErr("There was an error while programming.")
            return False

        printStdErr("\nGiving the Arduino 10 seconds to reset.")
        self.delay(10)
        return True
예제 #53
0
                oldSettings["controlConstants"] = json.loads(line[2:])
            elif line[0] == "S":
                oldSettings["controlSettings"] = json.loads(line[2:])
            elif line[0] == "d":
                oldSettings["installedDevices"] = json.loads(line[2:])

        except json.decoder.JSONDecodeError, e:
            printStdErr("JSON decode error: " + str(e))
            printStdErr("Line received was: " + line)

    ser.close()
    del ser  # Arduino won't reset when serial port is not completely removed
    oldSettingsFileName = "oldAvrSettings-" + time.strftime("%b-%d-%Y-%H-%M-%S") + ".json"
    printStdErr("Saving old settings to file " + oldSettingsFileName)

    scriptDir = util.scriptPath()  # <-- absolute dir the script is in
    if not os.path.exists(scriptDir + "/settings/avr-backup/"):
        os.makedirs(scriptDir + "/settings/avr-backup/")

    oldSettingsFile = open(scriptDir + "/settings/avr-backup/" + oldSettingsFileName, "wb")
    oldSettingsFile.write(json.dumps(oldSettings))

    oldSettingsFile.truncate()
    oldSettingsFile.close()

    printStdErr("Loading programming settings from board.txt")

    # parse the Arduino board file to get the right program settings
    for line in boardsFile:
        if line.startswith(boardType):
            # strip board name, period and \n
예제 #54
0
def programArduino(config, boardType, hexFile, restoreWhat):
    printStdErr("****    Arduino Program script started    ****")

    arduinohome = config.get('arduinoHome', '/usr/share/arduino/')  # location of Arduino sdk
    avrdudehome = config.get('avrdudeHome', arduinohome + 'hardware/tools/')  # location of avr tools
    avrsizehome = config.get('avrsizeHome', '')  # default to empty string because avrsize is on path
    avrconf = config.get('avrConf', avrdudehome + 'avrdude.conf')  # location of global avr conf

    boardsFile = loadBoardsFile(arduinohome)
    boardSettings = fetchBoardSettings(boardsFile, boardType)

    restoreSettings = False
    restoreDevices = False
    if 'settings' in restoreWhat:
        if restoreWhat['settings']:
            restoreSettings = True
    if 'devices' in restoreWhat:
        if restoreWhat['devices']:
            restoreDevices = True
    # Even when restoreSettings and restoreDevices are set to True here,
    # they might be set to false due to version incompatibility later

    printStdErr("Settings will " + ("" if restoreSettings else "not ") + "be restored" +
                (" if possible" if restoreSettings else ""))
    printStdErr("Devices will " + ("" if restoreDevices else "not ") + "be restored" +
                (" if possible" if restoreSettings else ""))

    ser, port = openSerial(config['port'], config['altport'], 57600, 0.2)
    if ser is None:
        printStdErr("Could not open serial port. Programming aborted.")
        return 0

    time.sleep(5)  # give the arduino some time to reboot in case of an Arduino UNO

    printStdErr("Checking old version before programming.")

    avrVersionOld = brewpiVersion.getVersionFromSerial(ser)
    if avrVersionOld is None:
        printStdErr(("Warning: Cannot receive version number from Arduino. " +
                     "Your Arduino is either not programmed yet or running a very old version of BrewPi. "
                     "Arduino will be reset to defaults."))
    else:
        printStdErr("Found " + avrVersionOld.toExtendedString() + \
                    " on port " + port + "\n")

    oldSettings = {}


    # request all settings from board before programming
    if avrVersionOld is not None:
        printStdErr("Requesting old settings from Arduino...")
        if avrVersionOld.minor > 1:  # older versions did not have a device manager
            ser.write("d{}")  # installed devices
            time.sleep(1)
        ser.write("c")  # control constants
        ser.write("s")  # control settings
        time.sleep(2)

        for line in ser:
            try:
                if line[0] == 'C':
                    oldSettings['controlConstants'] = json.loads(line[2:])
                elif line[0] == 'S':
                    oldSettings['controlSettings'] = json.loads(line[2:])
                elif line[0] == 'd':
                    oldSettings['installedDevices'] = json.loads(line[2:])

            except json.decoder.JSONDecodeError, e:
                printStdErr("JSON decode error: " + str(e))
                printStdErr("Line received was: " + line)

        oldSettingsFileName = 'oldAvrSettings-' + time.strftime("%b-%d-%Y-%H-%M-%S") + '.json'
        printStdErr("Saving old settings to file " + oldSettingsFileName)

        scriptDir = util.scriptPath()  # <-- absolute dir the script is in
        if not os.path.exists(scriptDir + '/settings/avr-backup/'):
            os.makedirs(scriptDir + '/settings/avr-backup/')

        oldSettingsFile = open(scriptDir + '/settings/avr-backup/' + oldSettingsFileName, 'wb')
        oldSettingsFile.write(json.dumps(oldSettings))

        oldSettingsFile.truncate()
        oldSettingsFile.close()
예제 #55
0
                    print "Updating system firmware for the {0}, part 2: {1}".format(device_type, system2)
                    p = subprocess.Popen(dfuPath + " -d {0} -a 0 -s 0x8060000 -D {1}".format(pid_vid[device_type], system2), shell=True)
                    p.wait()
                    time.sleep(1)

                print "Now writing BrewPi firmware {0} to {1}".format(binFile, device_type)
                p = subprocess.Popen(dfuPath + " -d {0} -a 0 -s 0x80A0000:leave -D {1}".format(pid_vid[device_type], binFile), shell=True)
                p.wait()
                time.sleep(1)

            print "Programming done"

            if not noReset:
                print "Now resetting EEPROM to defaults"
                # reset EEPROM to defaults
                configFile = util.scriptPath() + '/settings/config.cfg'
                config = util.readCfgWithDefaults(configFile)
                config_copy = config
                if 'socket:' in config['port']:
                    print "Socket configured as serial port, using auto detect to find USB serial"
                    config_copy['port'] = 'auto'

                programmer = SerialProgrammer.create(config_copy, device_type)
                # open serial port
                print "Opening serial port to reset factory defaults"
                if not programmer.open_serial_with_retry(config_copy, 57600, 1):
                    print "Could not open serial port after programming"
                else:
                    programmer.fetch_version("Success! ")
                    time.sleep(5)
                    programmer.reset_settings(testMode)