code: def add_node(self, node_descriptor):
          if self._max_nodes is not None and len(self.nodes) >= self._max_nodes:
              raise ResourceUsageError("Maximum number of nodes exceeded", max_nodes=self._max_nodes)
          node, inputs, processor = parse_node_descriptor(node_descriptor, self.model)
          in_root = False
          for i, input_data in enumerate(inputs):
              selector, trigger = input_data
              walker = self.sensor_log.create_walker(selector)
              if walker.selector.inexhaustible:
                  walker.reading = IOTileReading(0xFFFFFFFF, walker.selector.as_stream(), 0)
              node.connect_input(i, walker, trigger)
              if selector.input and not in_root:
                  self.roots.append(node)
                  in_root = True
              else:
                  found = False
                  for other in self.nodes:
                      if selector.matches(other.stream):
                          other.connect_output(node)
                          found = True
                  if not found and selector.buffered:
                      raise NodeConnectionError("Node has input that refers to another node that has not been created yet", node_descriptor=node_descriptor, input_selector=str(selector), input_index=i)
          for other_node in self.nodes:
              for selector, trigger in other_node.inputs:
                  if selector.matches(node.stream):
                      node.connect_output(other_node)
          func = self.find_processing_function(processor)
          if func is None:
              raise ProcessingFunctionError("Could not find processing function in installed packages", func_name=processor)
          node.set_func(processor, func)
          self.nodes.append(node)