def Run( trigger ): # Run through the rules looking to see if we have a match for the trigger rules = database.GetRules( trigger) # Get a list of all rules that mention trigger log.debug("Running rule: " + trigger) delVar = False if "==" in trigger: sep = trigger.index("==") triggerType = trigger[:sep] triggerVal = trigger[sep + 2:] oldVal = variables.Get(triggerType) if oldVal == None: # Check to see if this variable already exists and leave it alone if so variables.Set(triggerType, triggerVal) delVar = True for line in rules: ruleId = line[0] rule = ' '.join( line[1].split() ) # Compact multiple spaces into single ones and make each line into a rule ruleList = rule.split(" ") # Make each rule into a list if ruleList[0].lower() == "if": doIndex = FindItemInList("do", ruleList) # Safely look for "do" if doIndex != None: if ParseCondition( ruleList[1:doIndex], trigger ) == True: # Parse condition from element 1 (ie immediately after "if") to "do" Action(ruleList[doIndex + 1:], ruleId) # Do action # else skip rest of line # else assume the line is a comment and skip it # end of rules if delVar: variables.Del( triggerType) # Make sure we don't re-run the same trigger
def do_set(self, line): """set name value Set named variable to value""" if " " in line: argList = line.split(" ") name = argList[0] val = argList[1] variables.Set(name, val) else: variables.Del(line)
def SetVarFromAttr( devIdx, name, value ): # See if this attribute has an associated variable for user & rules if name == "attr" + zcl.Cluster.PowerConfig + ":" + zcl.Attribute.Batt_Percentage: SetTempVal(devIdx, "GetNextBatteryAfter", datetime.now() + timedelta(seconds=86400)) # Ask for battery every day #varName = GetUserNameFromDevIdx(devIdx)+"_BatteryPercentage" if value != "FF": varVal = int(value, 16) / 2 # Arrives in 0.5% increments #variables.Set(varName, varVal) #SetSynopsis(varName, str(varVal)) # Ready for the synopsis email SetStatus(devIdx, "Battery", str(varVal)) # For web page else: variables.Del(varName) if name == "attr" + zcl.Cluster.Temperature + ":" + zcl.Attribute.Celsius: #varName = GetUserNameFromDevIdx(devIdx)+"_TemperatureC" if value != "FF9C": # Don't know where this value comes from - should be "FFFF" varVal = int(value, 16) / 100 # Arrives in 0.01'C increments #variables.Set(varName, varVal) SetStatus(devIdx, "Temperature", str(varVal)) # For web page else: variables.Del(varName) if name == "attr" + zcl.Cluster.OnOff + ":" + zcl.Attribute.OnOffState: now = datetime.now() nowStr = now.strftime("%H:%M") varVal = int(value, 16) if varVal == 0: SetStatus(devIdx, "Other", "Turned Off @ " + nowStr) else: SetStatus(devIdx, "Other", "Turned On @ " + nowStr) if name == "attr" + zcl.Cluster.Basic + "." + zcl.Attribute.Manuf_Name: userName = GetUserNameFromDevIdx(devIdx) if userName.find("(New)") == 0: userName = userName + " " + value SetUserNameFromDevIdx(devIdx, userName) if name == "attr" + zcl.Cluster.Basic + "." + zcl.Attribute.Model_Name: userName = GetUserNameFromDevIdx(devIdx) if userName.find("(New)") == 0: userName = userName + " " + value SetUserNameFromDevIdx(devIdx, userName)
def Run( trigger ): # Run through the rules looking to see if we have a match for the trigger rulesFile = Path(rulesFilename) if rulesFile.is_file(): with open(rulesFilename) as rules: log.log("Running rule: " + trigger) if "==" in trigger: sep = trigger.index("==") triggerType = trigger[:sep] triggerVal = trigger[sep + 2:] variables.Set(triggerType, triggerVal) for line in rules: rule = ' '.join( line.split() ) # Compact multiple spaces into single ones and make each line into a rule ruleList = rule.split(" ") # Make each rule into a list if ruleList[0] == "if": doIndex = FindItemInList("do", ruleList) # Safely look for "do" if doIndex != None: if ParseCondition( ruleList[1:doIndex], trigger ) == True: # Parse condition from element 1 to "do" Action(ruleList[doIndex + 1:]) # Do action # else skip rest of line elif ruleList[0] == "do": Action(ruleList[1:]) # else assume the line is a comment and skip it # end of rules variables.Del( triggerType) # Make sure we don't re-run the same trigger else: shell.exec("touch " + rulesFilename) shell.exec("chmod 666 " + rulesFilename) log.fault("Made new " + rulesFilename + " !")
def Action(actList, ruleId): log.debug("Action with: " + str(actList)) action = actList[0].lower() if action == "Log".lower(): log.debug("Rule says Log event for " + ' '.join(actList[1:])) elif action == "Play".lower(): call(["omxplayer", "-o", actList[1], actList[2]]) elif action == "Event".lower(): if actList[1].lower() == "TimeOfDay".lower(): events.IssueEvent(events.ids.TIMEOFDAY, actList[2]) elif actList[1].lower() == "Alarm".lower(): events.IssueEvent(events.ids.ALARM, actList[2]) # Could have other events here... elif action == "synopsis": # Was status emailAddress = config.Get("emailAddress") log.debug("About to send synopsis to " + emailAddress) if emailAddress != None: synopsis.BuildPage() # Create synopsis page on demand with open("synopsis.txt", "r") as fh: # Plain text of email emailText = fh.readlines() text = ''.join(emailText) with open("synopsis.html", "r") as fh: # HTML of email emailHtml = fh.readlines() html = ''.join(emailHtml) sendmail.email("Vesta Status", text, html) # See sendmail.py else: synopsis.problem( "NoEmail", "No emailAddress entry in config, needed to send synopsis") elif action == "email": # All args are body of the text. Fixed subject and email address emailAddress = config.Get("emailAddress") if emailAddress != None: emailBody = [] for item in actList[1:]: emailBody.append(item) plainText = " ".join(emailBody) log.debug("Sending email with '" + plainText + "'") result = sendmail.email("Vesta Alert!", plainText, None) if result != 0: synopsis.problem( "Email", "sendmail.email() failed with code " + str(result) + " when trying to send:" + plainText) else: synopsis.problem("NoEmail", "No emailAddress entry in config") elif action == "override": # Syntax is "Override <targetDevice> <targetDegC> <durationSecs>" devKey = devices.FindDev(actList[1]) target = actList[2] timeSecs = actList[3] if devKey != None: schedule.Override(devKey, target, timeSecs) elif action == "set": # Set a named variable to a value expression = "".join( actList[1:] ) # First recombine actList[1] onwards, with no spaces. Now expression should be of the form "<var>=<val>" if "--" in expression: sep = expression.index("--") varName = expression[:sep] varVal = variables.Get(varName) if isNumber(varVal): newVal = str(eval(varVal + "-1")) variables.Set(varName, newVal) Run( varName + "==" + newVal ) # Recurse! to see if any rules need running now that we've set a variable else: log.fault(varName + " not a number at " + expression) elif "++" in expression: sep = expression.index("++") varName = expression[:sep] varVal = variables.Get(varName) if isNumber(varVal): newVal = str(eval(varVal + "+1")) variables.Set(varName, newVal) Run( varName + "==" + newVal ) # Recurse! to see if any rules need running now that we've set a variable else: log.fault(varName + " not a number at " + expression) elif "=" in expression: sep = expression.index("=") varName = expression[:sep] varVal = expression[sep + 1:] variables.Set(varName, varVal) Run( varName + "==" + varVal ) # Recurse! to see if any rules need running now that we've set a variable else: log.fault("Badly formatted rule at " + expression) elif action == "unset": # Remove a named variable variables.Del(actList[1]) else: # Must be a command for a device, or group of devices if len(actList) >= 2: # Check that we have a second arg... name = actList[1] # Second arg is name if database.IsGroupName(name): # Check if name is a groupName devKeyList = GetGroupDevs(name) for devKey in devKeyList: CommandDev(action, devKey, actList, ruleId) # Command each device in list else: devKey = database.GetDevKey("userName", name) CommandDev(action, devKey, actList, ruleId) # Command one device