def observer(old_value, new_value): new_expression_value = expression.expression(container) run = True if on_xml.get("value") is not None: run = run and (parse_logic_expression(on_xml.get("value")).expression(container) == new_expression_value) if on_xml.get("old_value") is not None and "value" in context: run = run and (parse_logic_expression(on_xml.get("old_value")).expression(container) == context["value"]) context["value"] = new_expression_value if run: eval_procedure(container, on_xml.getchildren(), expression_value=new_expression_value)
def handle_signal(container, on_xml, **kwargs): for k, v in kwargs.iteritems(): if on_xml.get(k): w = parse_logic_expression(on_xml.get(k)).expression(container) if w != v: logger.debug("Skipping %s because %s value %r != %r", etree.tostring(on_xml).strip(), k, w, v) return eval_procedure(container, on_xml.getchildren())
def setup_ons(config, container): for on_xml in config.xpath("/smarthome/on"): if on_xml.get("signal"): object, signal = on_xml.get("signal").split(".", 1) container.object_manager.connect_object_signal(object, signal, functools.partial(handle_signal, container, on_xml)) elif on_xml.get("expression") or on_xml.get("property"): expression = parse_logic_expression(on_xml.get("expression") or on_xml.get("property")) observer = create_expression_change_observer(container, on_xml, expression, {}) for property_pointer in expression.properties_involved: container.object_manager.add_object_property_change_observer(property_pointer.object_pointer.name, property_pointer.name, observer) else: raise ValueError("<on/> should specify signal or property to bind")
def logic_expression(s): return parse_logic_expression(s)
def eval_procedure(container, procedure, **kwargs): had_if = False eval_next_else = False for command in procedure: logger.debug("Evaluating %s", etree.tostring(command).strip()) if command.tag == "else": if not had_if: raise ValueError("Else witout preceding if") if eval_next_else: eval_procedure(container, command.getchildren(), **kwargs) else: logger.debug("Skipping this else because if condition was True") continue had_if = False eval_next_else = False if command.tag == "if": had_if = True condition = parse_logic_expression(command.get("condition")).expression(container, **kwargs) logger.debug("Condition value: %r", condition) if condition: eval_procedure(container, command.getchildren(), **kwargs) else: eval_next_else = True elif command.tag == "call": if command.get("method"): object, method = command.get("method").split(".") meth = getattr(container.object_manager.objects[object], method) result = meth(**{k: parse_logic_expression(v).expression(container, **kwargs) for k, v in command.attrib.iteritems() if k not in ("method",)}) if command.getchildren(): if not isinstance(result, Promise): raise ValueError("Command has children but did not returned a Promise") for child in command.getchildren(): getattr(result, "on_%s" % child.tag)(functools.partial(eval_procedure, container, child.getchildren(), **kwargs)) elif command.get("routine"): container.routine_manager.call_routine(command.get("routine")) elif command.tag == "set": object, property = command.get("property").split(".") expression = parse_logic_expression(command.get("value")) container.object_manager.objects[object].set_property(property, expression.expression(container, **kwargs)) elif command.tag == "async": container.worker_pool.run_task(functools.partial(eval_procedure, container, command.getchildren(), **kwargs)) elif command.tag == "wait": if command.get("seconds"): time.sleep(int(command.get("seconds"))) elif command.tag == "connect_pad": dst_object = container.object_manager.objects[command.get("dst_object")] dst_object.connect_to_pad(command.get("dst_pad"), command.get("src_object"), command.get("src_pad")) elif command.tag == "disconnect_pad": dst_object = container.object_manager.objects[command.get("dst_object")] dst_object.disconnect_from_pad(command.get("dst_pad"), command.get("src_object"), command.get("src_pad")) elif command.tag == "toggle_pad_connection": dst_object = container.object_manager.objects[command.get("dst_object")] dst_pad = command.get("dst_pad") if len(dst_object.dump_incoming_pad_connections().get(dst_pad, [])) == 0: dst_object.connect_to_pad(dst_pad, command.get("src_object"), command.get("src_pad")) else: dst_object.disconnect_all_from_pad(dst_pad) elif command.tag == "disconnect_all_from_pad": dst_object = container.object_manager.objects[command.get("dst_object")] dst_object.disconnect_all_from_pad(command.get("dst_pad")) else: raise ValueError("Unknown command: %s" % command.tag)