示例#1
0
 def __init__(self, config: ConfigHelper) -> None:
     self.server = config.get_server()
     self.last_print_stats: Dict[str, Any] = {}
     self.server.register_event_handler(
         "server:klippy_started", self._handle_started)
     self.server.register_event_handler(
         "server:status_update", self._status_update)
示例#2
0
 def __init__(self, config: ConfigHelper) -> None:
     self.server = config.get_server()
     self.ioloop = IOLoop.current()
     self.stat_update_cb = PeriodicCallback(
         self._handle_stat_update, STAT_UPDATE_TIME_MS)  # type: ignore
     self.vcgencmd: Optional[shell_command.ShellCommand] = None
     if os.path.exists(VC_GEN_CMD_FILE):
         logging.info("Detected 'vcgencmd', throttle checking enabled")
         shell_cmd: shell_command.ShellCommandFactory
         shell_cmd = self.server.load_component(config, "shell_command")
         self.vcgencmd = shell_cmd.build_shell_command(
             "vcgencmd get_throttled")
         self.server.register_notification("proc_stats:cpu_throttled")
     else:
         logging.info("Unable to find 'vcgencmd', throttle checking "
                      "disabled")
     self.temp_file = pathlib.Path(TEMPERATURE_PATH)
     self.smaps = pathlib.Path(STATM_FILE_PATH)
     self.server.register_endpoint(
         "/machine/proc_stats", ["GET"], self._handle_stat_request)
     self.server.register_event_handler(
         "server:klippy_shutdown", self._handle_shutdown)
     self.server.register_notification("proc_stats:proc_stat_update")
     self.proc_stat_queue: Deque[Dict[str, Any]] = deque(maxlen=30)
     self.last_update_time = time.time()
     self.last_proc_time = time.process_time()
     self.throttle_check_lock = Lock()
     self.total_throttled: int = 0
     self.last_throttled: int = 0
     self.update_sequence: int = 0
     self.stat_update_cb.start()
示例#3
0
 def __init__(self, config: ConfigHelper) -> None:
     name_parts = config.get_name().split(maxsplit=1)
     if len(name_parts) != 2:
         raise config.error(f"Invalid Section Name: {config.get_name()}")
     self.server = config.get_server()
     self.name = name_parts[1]
     self.type: str = config.get('type')
     self.state: str = "init"
     self.locked_while_printing = config.getboolean('locked_while_printing',
                                                    False)
     self.off_when_shutdown = config.getboolean('off_when_shutdown', False)
     self.off_when_shutdown_delay = 0.
     if self.off_when_shutdown:
         self.off_when_shutdown_delay = config.getfloat(
             'off_when_shutdown_delay', 0., minval=0.)
     self.shutdown_timer_handle: Optional[asyncio.TimerHandle] = None
     self.restart_delay = 1.
     self.klipper_restart = config.getboolean(
         'restart_klipper_when_powered', False)
     if self.klipper_restart:
         self.restart_delay = config.getfloat('restart_delay', 1.)
         if self.restart_delay < .000001:
             raise config.error("Option 'restart_delay' must be above 0.0")
     self.bound_service: Optional[str] = config.get('bound_service', None)
     self.need_scheduled_restart = False
     self.on_when_queued = config.getboolean('on_when_upload_queued', False)
示例#4
0
    def __init__(self, config: ConfigHelper) -> None:
        self.server = config.get_server()
        self.temp_store_size = config.getint('temperature_store_size', 1200)
        self.gcode_store_size = config.getint('gcode_store_size', 1000)

        # Temperature Store Tracking
        self.last_temps: Dict[str, Tuple[float, ...]] = {}
        self.gcode_queue: GCQueue = deque(maxlen=self.gcode_store_size)
        self.temperature_store: TempStore = {}
        self.temp_update_cb = PeriodicCallback(
            self._update_temperature_store, TEMPERATURE_UPDATE_MS)

        # Register status update event
        self.server.register_event_handler(
            "server:status_update", self._set_current_temps)
        self.server.register_event_handler(
            "server:gcode_response", self._update_gcode_store)
        self.server.register_event_handler(
            "server:klippy_ready", self._init_sensors)

        # Register endpoints
        self.server.register_endpoint(
            "/server/temperature_store", ['GET'],
            self._handle_temp_store_request)
        self.server.register_endpoint(
            "/server/gcode_store", ['GET'],
            self._handle_gcode_store_request)
示例#5
0
 def __init__(self, config: confighelper.ConfigHelper) -> None:
     self.server = config.get_server()
     self.uds_address: str = config.get(
         'klippy_uds_address', "/tmp/klippy_uds")
     self.writer: Optional[asyncio.StreamWriter] = None
     self.connection_mutex: asyncio.Lock = asyncio.Lock()
     self.event_loop = self.server.get_event_loop()
     self.log_no_access = True
     # Connection State
     self.connection_task: Optional[asyncio.Task] = None
     self.closing: bool = False
     self._klippy_info: Dict[str, Any] = {}
     self.init_list: List[str] = []
     self._klipper_version: str = ""
     self._missing_reqs: Set[str] = set()
     self._peer_cred: Dict[str, int] = {}
     self.init_attempts: int = 0
     self._state: str = "disconnected"
     self.subscriptions: Dict[Subscribable, Dict[str, Any]] = {}
     # Setup remote methods accessable to Klippy.  Note that all
     # registered remote methods should be of the notification type,
     # they do not return a response to Klippy after execution
     self.pending_requests: Dict[int, KlippyRequest] = {}
     self.remote_methods: Dict[str, FlexCallback] = {}
     self.klippy_reg_methods: List[str] = []
     self.register_remote_method(
         'process_gcode_response', self._process_gcode_response,
         need_klippy_reg=False)
     self.register_remote_method(
         'process_status_update', self._process_status_update,
         need_klippy_reg=False)
     self.server.register_component("klippy_connection", self)
示例#6
0
    def __init__(self: Strip, name: str, color_order: ColorOrder,
                 cfg: ConfigHelper):
        self.server = cfg.get_server()
        self.client = AsyncHTTPClient()
        self.request_mutex = asyncio.Lock()

        self.name = name
        self.color_order = color_order

        # Read the uri information
        addr: str = cfg.get("address")
        port: int = cfg.getint("port", 80)
        protocol: str = cfg.get("protocol", "http")
        self.url = f"{protocol}://{addr}:{port}/json"

        self.timeout: float = cfg.getfloat("timeout", 2.)

        self.initial_preset: int = cfg.getint("initial_preset", -1)
        self.initial_red: float = cfg.getfloat("initial_red", 0.5)
        self.initial_green: float = cfg.getfloat("initial_green", 0.5)
        self.initial_blue: float = cfg.getfloat("initial_blue", 0.5)
        self.initial_white: float = cfg.getfloat("initial_white", 0.5)
        self.chain_count: int = cfg.getint("chain_count", 1)

        self._chain_data = bytearray(self.chain_count *
                                     color_order.Elem_Size())

        self.onoff = OnOff.off
        self.preset = self.initial_preset
示例#7
0
    def __init__(self, config: ConfigHelper) -> None:
        self.server = config.get_server()
        dist_info: Dict[str, Any]
        dist_info = {'name': distro.name(pretty=True)}
        dist_info.update(distro.info())
        dist_info['release_info'] = distro.distro_release_info()
        self.inside_container = False
        self.system_info: Dict[str, Any] = {
            'python': {
                "version": sys.version_info,
                "version_string": sys.version.replace("\n", " ")
            },
            'cpu_info': self._get_cpu_info(),
            'sd_info': self._get_sdcard_info(),
            'distribution': dist_info,
            'virtualization': self._check_inside_container()
        }
        self._update_log_rollover(log=True)
        providers: Dict[str, type] = {
            "none": BaseProvider,
            "systemd_cli": SystemdCliProvider,
            "systemd_dbus": SystemdDbusProvider
        }
        ptype = config.get('provider', 'systemd_dbus')
        pclass = providers.get(ptype)
        if pclass is None:
            raise config.error(f"Invalid Provider: {ptype}")
        self.sys_provider: BaseProvider = pclass(config)
        logging.info(f"Using System Provider: {ptype}")

        self.server.register_endpoint("/machine/reboot", ['POST'],
                                      self._handle_machine_request)
        self.server.register_endpoint("/machine/shutdown", ['POST'],
                                      self._handle_machine_request)
        self.server.register_endpoint("/machine/services/restart", ['POST'],
                                      self._handle_service_request)
        self.server.register_endpoint("/machine/services/stop", ['POST'],
                                      self._handle_service_request)
        self.server.register_endpoint("/machine/services/start", ['POST'],
                                      self._handle_service_request)
        self.server.register_endpoint("/machine/system_info", ['GET'],
                                      self._handle_sysinfo_request)

        self.server.register_notification("machine:service_state_changed")

        # Register remote methods
        self.server.register_remote_method("shutdown_machine",
                                           self.sys_provider.shutdown)
        self.server.register_remote_method("reboot_machine",
                                           self.sys_provider.reboot)

        # IP network shell commands
        shell_cmd: SCMDComp = self.server.load_component(
            config, 'shell_command')
        self.addr_cmd = shell_cmd.build_shell_command("ip -json address")
        iwgetbin = "/sbin/iwgetid"
        if not pathlib.Path(iwgetbin).exists():
            iwgetbin = "iwgetid"
        self.iwgetid_cmd = shell_cmd.build_shell_command(iwgetbin)
        self.init_evt = asyncio.Event()
示例#8
0
    def __init__(self, config: ConfigHelper) -> None:

        self.config = config
        name_parts = config.get_name().split(maxsplit=1)
        if len(name_parts) != 2:
            raise config.error(f"Invalid Section Name: {config.get_name()}")
        self.server = config.get_server()
        self.name = name_parts[1]
        self.apprise = apprise.Apprise()
        self.warned = False

        self.attach_requires_file_system_check = True
        self.attach = config.get("attach", None)
        if self.attach is None or \
            (self.attach.startswith("http://") or
             self.attach.startswith("https://")):
            self.attach_requires_file_system_check = False

        url_template = config.gettemplate('url')
        self.url = url_template.render()

        if len(self.url) < 2:
            raise config.error(f"Invalid url for: {config.get_name()}")

        self.title = config.gettemplate('title', None)
        self.body = config.gettemplate("body", None)

        self.events: List[str] = config.getlist("events", separator=",")

        self.apprise.add(self.url)
示例#9
0
    def __init__(self, config: ConfigHelper) -> None:
        self.server = config.get_server()
        self.temp_store_size = config.getint('temperature_store_size', 1200)
        self.gcode_store_size = config.getint('gcode_store_size', 1000)

        # Temperature Store Tracking
        self.last_temps: Dict[str, Tuple[float, ...]] = {}
        self.gcode_queue: GCQueue = deque(maxlen=self.gcode_store_size)
        self.temperature_store: TempStore = {}
        eventloop = self.server.get_event_loop()
        self.temp_update_timer = eventloop.register_timer(
            self._update_temperature_store)

        # Register status update event
        self.server.register_event_handler("server:status_update",
                                           self._set_current_temps)
        self.server.register_event_handler("server:gcode_response",
                                           self._update_gcode_store)
        self.server.register_event_handler("server:klippy_ready",
                                           self._init_sensors)
        self.server.register_event_handler("klippy_connection:gcode_received",
                                           self._store_gcode_command)

        # Register endpoints
        self.server.register_endpoint("/server/temperature_store", ['GET'],
                                      self._handle_temp_store_request)
        self.server.register_endpoint("/server/gcode_store", ['GET'],
                                      self._handle_gcode_store_request)
示例#10
0
 def __init__(self, config: ConfigHelper) -> None:
     self.server = config.get_server()
     self.gpiod: Any = load_system_module("gpiod")
     self.chips: Dict[str, Any] = {}
     self.reserved_gpios: Dict[str, GpioOutputPin] = {}
     version: str = self.gpiod.version_string()
     self.gpiod_version = tuple(int(v) for v in version.split('.'))
示例#11
0
    def __init__(self, config: ConfigHelper) -> None:
        self.server = config.get_server()
        self.debug_enabled = config.getboolean('enable_repo_debug', False)
        if self.debug_enabled:
            logging.warning("UPDATE MANAGER: REPO DEBUG ENABLED")
        shell_cmd: SCMDComp = self.server.lookup_component('shell_command')
        self.scmd_error = shell_cmd.error
        self.build_shell_command = shell_cmd.build_shell_command
        self.pkg_updater: Optional[PackageDeploy] = None
        self.http_client = AsyncHTTPClient()
        self.github_request_cache: Dict[str, CachedGithubResponse] = {}

        # database management
        db: DBComp = self.server.lookup_component('database')
        db.register_local_namespace("update_manager")
        self.umdb = db.wrap_namespace("update_manager")

        # Refresh Time Tracking (default is to refresh every 28 days)
        reresh_interval = config.getint('refresh_interval', 672)
        # Convert to seconds
        self.refresh_interval = reresh_interval * 60 * 60

        # GitHub API Rate Limit Tracking
        self.gh_rate_limit: Optional[int] = None
        self.gh_limit_remaining: Optional[int] = None
        self.gh_limit_reset_time: Optional[float] = None

        # Update In Progress Tracking
        self.cur_update_app: Optional[str] = None
        self.cur_update_id: Optional[int] = None
        self.full_complete: bool = False
示例#12
0
    def __init__(self, config: ConfigHelper) -> None:
        self.server = config.get_server()
        self.namespaces: Dict[str, object] = {}
        self.enable_debug = config.getboolean("enable_database_debug", False)
        self.database_path = os.path.expanduser(
            config.get('database_path', "~/.moonraker_database"))
        if not os.path.isdir(self.database_path):
            os.mkdir(self.database_path)
        self.lmdb_env = lmdb.open(self.database_path,
                                  map_size=MAX_DB_SIZE,
                                  max_dbs=MAX_NAMESPACES)
        with self.lmdb_env.begin(write=True, buffers=True) as txn:
            # lookup existing namespaces
            cursor = txn.cursor()
            remaining = cursor.first()
            while remaining:
                key = bytes(cursor.key())
                self.namespaces[key.decode()] = self.lmdb_env.open_db(key, txn)
                remaining = cursor.next()
            cursor.close()
            if "moonraker" not in self.namespaces:
                mrdb = self.lmdb_env.open_db(b"moonraker", txn)
                self.namespaces["moonraker"] = mrdb
                txn.put(b'database_version',
                        self._encode_value(DATABASE_VERSION),
                        db=mrdb)
        # Read out all namespaces to remove any invalid keys on init
        for ns in self.namespaces.keys():
            self._get_namespace(ns)
        # Protected Namespaces have read-only API access.  Write access can
        # be granted by enabling the debug option.  Forbidden namespaces
        # have no API access.  This cannot be overridden.
        self.protected_namespaces = set(
            self.get_item("moonraker", "database.protected_namespaces",
                          ["moonraker"]))
        self.forbidden_namespaces = set(
            self.get_item("moonraker", "database.forbidden_namespaces", []))
        debug_counter: int = self.get_item("moonraker",
                                           "database.debug_counter", 0)
        if self.enable_debug:
            debug_counter += 1
            self.insert_item("moonraker", "database.debug_counter",
                             debug_counter)
        if debug_counter:
            logging.info(f"Database Debug Count: {debug_counter}")

        # Track unsafe shutdowns
        unsafe_shutdowns: int = self.get_item("moonraker",
                                              "database.unsafe_shutdowns", 0)
        logging.info(f"Unsafe Shutdown Count: {unsafe_shutdowns}")
        # Increment unsafe shutdown counter.  This will be reset if
        # moonraker is safely restarted
        self.insert_item("moonraker", "database.unsafe_shutdowns",
                         unsafe_shutdowns + 1)
        self.server.register_endpoint("/server/database/list", ['GET'],
                                      self._handle_list_request)
        self.server.register_endpoint("/server/database/item",
                                      ["GET", "POST", "DELETE"],
                                      self._handle_item_request)
示例#13
0
 def __init__(self, config: ConfigHelper) -> None:
     self.server = config.get_server()
     secrets: Secrets = self.server.load_component(config, 'secrets')
     self.jenv = jinja2.Environment('{%', '%}', '{', '}')
     self.jenv.add_extension("jinja2.ext.do")
     self.jenv.filters['fromjson'] = json.loads
     self.add_environment_global('raise_error', self._raise_error)
     self.add_environment_global('secrets', secrets)
示例#14
0
 def test_get_gpio_deprecated(self, gpio_config: ConfigHelper):
     server = gpio_config.get_server()
     gpio_config.getgpioout("test_gpio", deprecate=True)
     expected = (
         f"[test_options]: Option 'test_gpio' is "
         "deprecated, see the configuration documention "
         "at https://moonraker.readthedocs.io/en/latest/configuration")
     assert expected in server.warnings
示例#15
0
    def __init__(self, identifier: str, event_name: str, config: ConfigHelper):
        self.identifier = identifier
        self.event_name = event_name
        self.server = config.get_server()
        self.notifiers: Dict[str, NotifierInstance] = {}
        self.config = config

        self.server.register_event_handler(self.event_name, self._handle)
示例#16
0
 def test_get_template_deprecate(self, test_config: ConfigHelper):
     server = test_config.get_server()
     test_config.gettemplate("test_template", deprecate=True)
     expected = (
         f"[test_options]: Option 'test_template' is "
         "deprecated, see the configuration documention "
         "at https://moonraker.readthedocs.io/en/latest/configuration")
     assert expected in server.warnings
示例#17
0
    def __init__(self, config: ConfigHelper) -> None:
        self.server = config.get_server()
        self.client = AsyncHTTPClient()
        self.response_cache: Dict[str, HttpResponse] = {}

        self.gh_rate_limit: Optional[int] = None
        self.gh_limit_remaining: Optional[int] = None
        self.gh_limit_reset_time: Optional[float] = None
示例#18
0
    def __init__(self: WLED, config: ConfigHelper) -> None:
        # root_logger = logging.getLogger()
        # root_logger.setLevel(logging.DEBUG)

        self.server = config.get_server()
        prefix_sections = config.get_prefix_sections("wled")
        logging.info(f"WLED component loading strips: {prefix_sections}")

        strip_types = {"HTTP": StripHttp, "SERIAL": StripSerial}
        self.strips = {}
        for section in prefix_sections:
            cfg = config[section]

            try:
                name_parts = cfg.get_name().split(maxsplit=1)
                if len(name_parts) != 2:
                    raise cfg.error(f"Invalid Section Name: {cfg.get_name()}")
                name: str = name_parts[1]

                logging.info(f"WLED strip: {name}")

                # Discard old color_order setting, always support 4 color strips
                _ = cfg.get("color_order", "", deprecate=True)

                strip_type: str = cfg.get("type", "http")
                strip_class: Optional[Type[Strip]]
                strip_class = strip_types.get(strip_type.upper())
                if strip_class is None:
                    raise config.error(f"Unsupported Strip Type: {strip_type}")

                self.strips[name] = strip_class(name, cfg)

            except Exception as e:
                # Ensures errors such as "Color not supported" are visible
                msg = f"Failed to initialise strip [{cfg.get_name()}]\n{e}"
                self.server.add_warning(msg)
                continue

        # Register two remote methods for GCODE
        self.server.register_remote_method("set_wled_state",
                                           self.set_wled_state)
        self.server.register_remote_method("set_wled", self.set_wled)

        # As moonraker is about making things a web api, let's try it
        # Yes, this is largely a cut-n-paste from power.py
        self.server.register_endpoint("/machine/wled/strips", ["GET"],
                                      self._handle_list_strips)
        self.server.register_endpoint("/machine/wled/status", ["GET"],
                                      self._handle_batch_wled_request)
        self.server.register_endpoint("/machine/wled/on", ["POST"],
                                      self._handle_batch_wled_request)
        self.server.register_endpoint("/machine/wled/off", ["POST"],
                                      self._handle_batch_wled_request)
        self.server.register_endpoint("/machine/wled/toggle", ["POST"],
                                      self._handle_batch_wled_request)
        self.server.register_endpoint("/machine/wled/strip", ["GET", "POST"],
                                      self._handle_single_wled_request)
示例#19
0
 def __init__(self, config: ConfigHelper) -> None:
     self.server = config.get_server()
     database: MoonrakerDatabase
     database = self.server.lookup_component("database")
     database.register_local_namespace("announcements")
     self.announce_db = database.wrap_namespace("announcements")
     self.entry_id_map: Dict[str, str] = {}
     self.next_key = 0
     self.dismiss_handles: Dict[str, asyncio.TimerHandle] = {}
示例#20
0
    def __init__(self, config: ConfigHelper) -> None:
        self.server = config.get_server()
        self.software_version = config['system_args'].get('software_version')

        # Local variables
        self.klippy_apis: APIComp = self.server.lookup_component('klippy_apis')
        self.heaters: Dict[str, Dict[str, Any]] = {}
        self.last_print_stats: Dict[str, Any] = {}

        # Register status update event
        self.server.register_event_handler('server:klippy_ready', self._init)
        self.server.register_event_handler('server:status_update',
                                           self._handle_status_update)

        # Version & Server information
        self.server.register_endpoint('/api/version', ['GET'],
                                      self._get_version,
                                      wrap_result=False)
        self.server.register_endpoint('/api/server', ['GET'],
                                      self._get_server,
                                      wrap_result=False)

        # Login, User & Settings
        self.server.register_endpoint('/api/login', ['POST'],
                                      self._post_login_user,
                                      wrap_result=False)
        self.server.register_endpoint('/api/currentuser', ['GET'],
                                      self._post_login_user,
                                      wrap_result=False)
        self.server.register_endpoint('/api/settings', ['GET'],
                                      self._get_settings,
                                      wrap_result=False)

        # File operations
        # Note that file upload is handled in file_manager.py
        # TODO: List/info/select/delete files

        # Job operations
        self.server.register_endpoint('/api/job', ['GET'],
                                      self._get_job,
                                      wrap_result=False)
        # TODO: start/cancel/restart/pause jobs

        # Printer operations
        self.server.register_endpoint('/api/printer', ['GET'],
                                      self._get_printer,
                                      wrap_result=False)
        self.server.register_endpoint('/api/printer/command', ['POST'],
                                      self._post_command,
                                      wrap_result=False)
        # TODO: head/tool/bed/chamber specific read/issue

        # Printer profiles
        self.server.register_endpoint('/api/printerprofiles', ['GET'],
                                      self._get_printerprofiles,
                                      wrap_result=False)
示例#21
0
 def __init__(self, config: ConfigHelper) -> None:
     self.server = config.get_server()
     self.gpiod: Any = load_system_module("gpiod")
     GpioEvent.init_constants(self.gpiod)
     self.chips: Dict[str, Any] = {}
     self.reserved_gpios: Dict[str, GpioBase] = {}
     version: str = self.gpiod.version_string()
     self.gpiod_version = tuple(int(v) for v in version.split('.'))
     self.server.add_log_rollover_item("gpiod_version",
                                       f"libgpiod version: {version}")
示例#22
0
 def __init__(self, config: ConfigHelper) -> None:
     self.server = config.get_server()
     self.runner = AsyncRunner(IPVersion.All)
     hi = self.server.get_host_info()
     addresses: Optional[List[bytes]] = [socket.inet_aton(hi["address"])]
     self.bound_all = hi["address"] == "0.0.0.0"
     self.service_info = self._build_service_info(addresses)
     if self.bound_all:
         self.server.register_event_handler(
             "machine:net_state_changed", self._update_service)
示例#23
0
 def __init__(self, config: ConfigHelper) -> None:
     self.server = config.get_server()
     self.agents: Dict[str, WebSocket] = {}
     self.server.register_endpoint("/connection/send_event", ["POST"],
                                   self._handle_agent_event,
                                   transports=["websocket"])
     self.server.register_endpoint("/server/extensions/list", ["GET"],
                                   self._handle_list_extensions)
     self.server.register_endpoint("/server/extensions/request", ["POST"],
                                   self._handle_call_agent)
示例#24
0
    def __init__(self, config: ConfigHelper) -> None:
        self.server = config.get_server()
        if not HAS_GPIOD:
            self.server.add_warning("Unable to load gpiod library, GPIO power "
                                    "devices will not be loaded")
        self.chip_factory = GpioChipFactory()
        self.devices: Dict[str, PowerDevice] = {}
        prefix_sections = config.get_prefix_sections("power")
        logging.info(f"Power component loading devices: {prefix_sections}")
        dev_types = {
            "gpio": GpioDevice,
            "tplink_smartplug": TPLinkSmartPlug,
            "tasmota": Tasmota,
            "shelly": Shelly,
            "homeseer": HomeSeer,
            "homeassistant": HomeAssistant,
            "loxonev1": Loxonev1
        }
        try:
            for section in prefix_sections:
                cfg = config[section]
                dev_type: str = cfg.get("type")
                dev_class: Optional[Type[PowerDevice]]
                dev_class = dev_types.get(dev_type)
                if dev_class is None:
                    raise config.error(f"Unsupported Device Type: {dev_type}")
                dev = dev_class(cfg)
                if isinstance(dev, GpioDevice):
                    if not HAS_GPIOD:
                        continue
                    dev.configure_line(cfg, self.chip_factory)
                self.devices[dev.get_name()] = dev
        except Exception:
            self.chip_factory.close()
            raise

        self.server.register_endpoint("/machine/device_power/devices", ['GET'],
                                      self._handle_list_devices)
        self.server.register_endpoint("/machine/device_power/status", ['GET'],
                                      self._handle_batch_power_request)
        self.server.register_endpoint("/machine/device_power/on", ['POST'],
                                      self._handle_batch_power_request)
        self.server.register_endpoint("/machine/device_power/off", ['POST'],
                                      self._handle_batch_power_request)
        self.server.register_endpoint("/machine/device_power/device",
                                      ['GET', 'POST'],
                                      self._handle_single_power_request)
        self.server.register_remote_method("set_device_power",
                                           self.set_device_power)
        self.server.register_event_handler("server:klippy_shutdown",
                                           self._handle_klippy_shutdown)
        self.server.register_notification("power:power_changed")
        event_loop = self.server.get_event_loop()
        event_loop.register_callback(self._initalize_devices,
                                     list(self.devices.values()))
示例#25
0
    def __init__(self, config: ConfigHelper) -> None:
        self.server = config.get_server()
        self.entry_mgr = EntryManager(config)
        self.eventloop = self.server.get_event_loop()
        self.update_timer = self.eventloop.register_timer(
            self._handle_update_timer
        )
        self.request_lock = asyncio.Lock()
        self.dev_mode = config.getboolean("dev_mode", False)
        self.subscriptions: Dict[str, RssFeed] = {
            "moonraker": RssFeed("moonraker", self.entry_mgr, self.dev_mode),
            "klipper": RssFeed("klipper", self.entry_mgr, self.dev_mode)
        }
        self.stored_feeds: List[str] = []
        sub_list: List[str] = config.getlist("subscriptions", [])
        self.configured_feeds: List[str] = ["moonraker", "klipper"]
        for sub in sub_list:
            sub = sub.lower()
            if sub in self.subscriptions:
                continue
            self.configured_feeds.append(sub)
            self.subscriptions[sub] = RssFeed(
                sub, self.entry_mgr, self.dev_mode
            )

        self.server.register_endpoint(
            "/server/announcements/list", ["GET"],
            self._list_announcements
        )
        self.server.register_endpoint(
            "/server/announcements/dismiss", ["POST"],
            self._handle_dismiss_request
        )
        self.server.register_endpoint(
            "/server/announcements/update", ["POST"],
            self._handle_update_request
        )
        self.server.register_endpoint(
            "/server/announcements/feed", ["POST", "DELETE"],
            self._handle_feed_request
        )
        self.server.register_endpoint(
            "/server/announcements/feeds", ["GET"],
            self._handle_list_feeds
        )
        self.server.register_notification(
            "announcements:dismissed", "announcement_dismissed"
        )
        self.server.register_notification(
            "announcements:entries_updated", "announcement_update"
        )
        self.server.register_notification(
            "announcements:dismiss_wake", "announcement_wake"
        )
示例#26
0
    def __init__(self, config: ConfigHelper) -> None:
        self.server = config.get_server()
        self.devices: Dict[str, PowerDevice] = {}
        prefix_sections = config.get_prefix_sections("power")
        logging.info(f"Power component loading devices: {prefix_sections}")
        dev_types = {
            "gpio": GpioDevice,
            "tplink_smartplug": TPLinkSmartPlug,
            "tasmota": Tasmota,
            "shelly": Shelly,
            "homeseer": HomeSeer,
            "homeassistant": HomeAssistant,
            "loxonev1": Loxonev1,
            "rf": RFDevice,
            "mqtt": MQTTDevice
        }

        for section in prefix_sections:
            cfg = config[section]
            dev_type: str = cfg.get("type")
            dev_class: Optional[Type[PowerDevice]]
            dev_class = dev_types.get(dev_type)
            if dev_class is None:
                raise config.error(f"Unsupported Device Type: {dev_type}")
            try:
                dev = dev_class(cfg)
            except Exception as e:
                msg = f"Failed to load power device [{cfg.get_name()}]\n{e}"
                self.server.add_warning(msg)
                continue
            self.devices[dev.get_name()] = dev

        self.server.register_endpoint(
            "/machine/device_power/devices", ['GET'],
            self._handle_list_devices)
        self.server.register_endpoint(
            "/machine/device_power/status", ['GET'],
            self._handle_batch_power_request)
        self.server.register_endpoint(
            "/machine/device_power/on", ['POST'],
            self._handle_batch_power_request)
        self.server.register_endpoint(
            "/machine/device_power/off", ['POST'],
            self._handle_batch_power_request)
        self.server.register_endpoint(
            "/machine/device_power/device", ['GET', 'POST'],
            self._handle_single_power_request)
        self.server.register_remote_method(
            "set_device_power", self.set_device_power)
        self.server.register_event_handler(
            "server:klippy_shutdown", self._handle_klippy_shutdown)
        self.server.register_event_handler(
            "file_manager:upload_queued", self._handle_upload_queued)
        self.server.register_notification("power:power_changed")
示例#27
0
    def __init__(self, config: ConfigHelper) -> None:
        self.server = config.get_server()
        self.http_server: Optional[HTTPServer] = None
        self.secure_server: Optional[HTTPServer] = None
        self.api_cache: Dict[str, APIDefinition] = {}
        self.registered_base_handlers: List[str] = []
        self.max_upload_size = config.getint('max_upload_size', 1024)
        self.max_upload_size *= 1024 * 1024

        # SSL config
        self.cert_path: str = self._get_path_option(
            config, 'ssl_certificate_path')
        self.key_path: str = self._get_path_option(
            config, 'ssl_key_path')

        # Set Up Websocket and Authorization Managers
        self.wsm = WebsocketManager(self.server)
        self.api_transports: Dict[str, APITransport] = {
            "websocket": self.wsm
        }

        mimetypes.add_type('text/plain', '.log')
        mimetypes.add_type('text/plain', '.gcode')
        mimetypes.add_type('text/plain', '.cfg')

        self.debug = config.getboolean('enable_debug_logging', False)
        log_level = logging.DEBUG if self.debug else logging.INFO
        logging.getLogger().setLevel(log_level)
        app_args: Dict[str, Any] = {
            'serve_traceback': self.debug,
            'websocket_ping_interval': 10,
            'websocket_ping_timeout': 30,
            'parent': self,
            'default_handler_class': AuthorizedErrorHandler,
            'default_handler_args': {},
            'log_function': self.log_request
        }

        # Set up HTTP only requests
        self.mutable_router = MutableRouter(self)
        app_handlers: List[Any] = [
            (AnyMatches(), self.mutable_router),
            (r"/websocket", WebSocket),
            (r"/server/redirect", RedirectHandler)]
        self.app = tornado.web.Application(app_handlers, **app_args)
        self.get_handler_delegate = self.app.get_handler_delegate

        # Register handlers
        logfile = self.server.get_app_args().get('log_file')
        if logfile:
            self.register_static_file_handler(
                "moonraker.log", logfile, force=True)
        self.register_static_file_handler(
            "klippy.log", DEFAULT_KLIPPY_LOG_PATH, force=True)
示例#28
0
def gpio_config(test_config: ConfigHelper,
                monkeypatch: pytest.MonkeyPatch) -> ConfigHelper:
    def load_gpio_mock(name: str) -> MockGpiod:
        return MockGpiod()

    monkeypatch.setattr(gpio, "load_system_module", load_gpio_mock)
    yield test_config
    server = test_config.get_server()
    gpio_comp = server.lookup_component("gpio", None)
    if gpio_comp is not None:
        gpio_comp.close()
        gpio_comp.reserved_gpios = {}
示例#29
0
 def __init__(self, config: ConfigHelper, paneldue: PanelDue) -> None:
     self.event_loop = config.get_server().get_event_loop()
     self.paneldue = paneldue
     self.port: str = config.get('serial')
     self.baud = config.getint('baud', 57600)
     self.partial_input: bytes = b""
     self.ser: Optional[serial.Serial] = None
     self.fd: Optional[int] = None
     self.connected: bool = False
     self.send_busy: bool = False
     self.send_buffer: bytes = b""
     self.attempting_connect: bool = True
示例#30
0
    def __init__(self, config: ConfigHelper) -> None:
        self.server = config.get_server()
        self.file_manager: FileManager = self.server.lookup_component(
            'file_manager')
        self.request_lock = Lock()
        database: DBComp = self.server.lookup_component("database")
        self.job_totals: Dict[str, float] = database.get_item(
            "moonraker", "history.job_totals",
            {
                'total_jobs': 0,
                'total_time': 0.,
                'total_print_time': 0.,
                'total_filament_used': 0.,
                'longest_job': 0.,
                'longest_print': 0.
            }).result()

        self.server.register_event_handler(
            "server:klippy_disconnect", self._handle_disconnect)
        self.server.register_event_handler(
            "server:klippy_shutdown", self._handle_shutdown)
        self.server.register_event_handler(
            "job_state:started", self._on_job_started)
        self.server.register_event_handler(
            "job_state:complete", self._on_job_complete)
        self.server.register_event_handler(
            "job_state:cancelled", self._on_job_cancelled)
        self.server.register_event_handler(
            "job_state:standby", self._on_job_standby)
        self.server.register_event_handler(
            "job_state:error", self._on_job_error)
        self.server.register_notification("history:history_changed")

        self.server.register_endpoint(
            "/server/history/job", ['GET', 'DELETE'], self._handle_job_request)
        self.server.register_endpoint(
            "/server/history/list", ['GET'], self._handle_jobs_list)
        self.server.register_endpoint(
            "/server/history/totals", ['GET'], self._handle_job_totals)
        self.server.register_endpoint(
            "/server/history/reset_totals", ['POST'],
            self._handle_job_total_reset)

        database.register_local_namespace(HIST_NAMESPACE)
        self.history_ns = database.wrap_namespace(HIST_NAMESPACE,
                                                  parse_keys=False)

        self.current_job: Optional[PrinterJob] = None
        self.current_job_id: Optional[str] = None
        self.next_job_id: int = 0
        self.cached_job_ids = self.history_ns.keys().result()
        if self.cached_job_ids:
            self.next_job_id = int(self.cached_job_ids[-1], 16) + 1