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)
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))
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 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)
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)
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
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()
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'
# 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
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):
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
# 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), '°') 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')
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):
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):
# request settings from Arduino, processed later when reply is received ser.write("s") # request control settings cs ser.write("c") # request control constants cc # answer from Arduino is received asynchronously later. # create a listening socket to communicate with PHP is_windows = sys.platform.startswith("win") useInetSocket = bool(config.get("useInetSocket", is_windows)) if useInetSocket: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) port = config.get("socketPort", 6332) s.bind((config.get("socketHost", "localhost"), int(port))) logMessage("Bound to TCP socket on port %d " % port) else: socketFile = util.addSlash(config["scriptPath"]) + "BEERSOCKET" if os.path.exists(socketFile): # if socket already exists, remove it os.remove(socketFile) s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(socketFile) # Bind BEERSOCKET # set all permissions for socket os.chmod(socketFile, 0777) serialCheckInterval = 0.5 s.setblocking(1) # set socket functions to be blocking s.listen(10) # Create a backlog queue for up to 10 connections # blocking socket functions wait 'serialCheckInterval' seconds s.settimeout(serialCheckInterval)