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)
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()))
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")
def __init__(self: WLED, config: ConfigHelper) -> None: try: # 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}") color_orders = {"RGB": ColorOrder.RGB, "RGBW": ColorOrder.RGBW} self.strips = {} for section in prefix_sections: cfg = config[section] 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}") color_order_cfg: str = cfg.get("color_order", "RGB") color_order = color_orders.get(color_order_cfg) if color_order is None: raise config.error( f"Color order not supported: {color_order_cfg}") self.strips[name] = Strip(name, color_order, cfg) # 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/strip", ["GET", "POST"], self._handle_single_wled_request) except Exception as e: logging.exception(e)
def __init__(self, config: ConfigHelper) -> None: self.server = config.get_server() self.buttons: Dict[str, GpioButton] = {} prefix_sections = config.get_prefix_sections("button") logging.info(f"Loading Buttons: {prefix_sections}") for section in prefix_sections: cfg = config[section] # Reserve the "type" option for future use btn_type = cfg.get('type', "gpio") try: btn = GpioButton(cfg) except Exception as e: msg = f"Failed to load button [{cfg.get_name()}]\n{e}" self.server.add_warning(msg) continue self.buttons[btn.name] = btn self.server.register_notification("button:button_event")
def __init__(self, config: ConfigHelper) -> None: self.server = config.get_server() self.webcams: Dict[str, WebCam] = {} # parse user configured webcams prefix_sections = config.get_prefix_sections("webcam ") for section in prefix_sections: cam_cfg = config[section] webcam = WebCam.from_config(cam_cfg) self.webcams[webcam.name] = webcam self.server.register_endpoint("/server/webcams/list", ["GET"], self._handle_webcam_list) self.server.register_endpoint("/server/webcams/item", ["GET", "POST", "DELETE"], self._handle_webcam_request) self.server.register_endpoint("/server/webcams/test", ["POST"], self._handle_webcam_test) self.server.register_notification("webcam:webcams_changed")
def __init__(self, config: ConfigHelper) -> None: self.server = config.get_server() self.notifiers: Dict[str, NotifierInstance] = {} self.events: Dict[str, NotifierEvent] = {} prefix_sections = config.get_prefix_sections("notifier") self.register_events(config) for section in prefix_sections: cfg = config[section] try: notifier = NotifierInstance(cfg) for event in self.events: if event in notifier.events or "*" in notifier.events: self.events[event].register_notifier(notifier) logging.info(f"Registered notifier: '{notifier.get_name()}'") except Exception as e: msg = f"Failed to load notifier[{cfg.get_name()}]\n{e}" self.server.add_warning(msg) continue self.notifiers[notifier.get_name()] = notifier
def __init__(self, config: ConfigHelper) -> None: self.server = config.get_server() self.event_loop = self.server.get_event_loop() self.app_config = config.read_supplemental_config( SUPPLEMENTAL_CFG_PATH) auto_refresh_enabled = config.getboolean('enable_auto_refresh', False) self.channel = config.get('channel', "dev") if self.channel not in ["dev", "beta"]: raise config.error( f"Unsupported channel '{self.channel}' in section" " [update_manager]") self.cmd_helper = CommandHelper(config) self.updaters: Dict[str, BaseDeploy] = {} if config.getboolean('enable_system_updates', True): self.updaters['system'] = PackageDeploy(config, self.cmd_helper) if ( os.path.exists(KLIPPER_DEFAULT_PATH) and os.path.exists(KLIPPER_DEFAULT_EXEC) ): self.updaters['klipper'] = get_deploy_class(KLIPPER_DEFAULT_PATH)( self.app_config[f"update_manager klipper"], self.cmd_helper, { 'channel': self.channel, 'path': KLIPPER_DEFAULT_PATH, 'executable': KLIPPER_DEFAULT_EXEC }) else: self.updaters['klipper'] = BaseDeploy( self.app_config[f"update_manager klipper"], self.cmd_helper) self.updaters['moonraker'] = get_deploy_class(MOONRAKER_PATH)( self.app_config[f"update_manager moonraker"], self.cmd_helper, { 'channel': self.channel, 'path': MOONRAKER_PATH, 'executable': sys.executable }) # TODO: The below check may be removed when invalid config options # raise a config error. if ( config.get("client_repo", None) is not None or config.get('client_path', None) is not None ): raise config.error( "The deprecated 'client_repo' and 'client_path' options\n" "have been removed. See Moonraker's configuration docs\n" "for details on client configuration.") client_sections = config.get_prefix_sections("update_manager ") for section in client_sections: cfg = config[section] name = section.split()[-1] if name in self.updaters: raise config.error(f"Client repo {name} already added") client_type = cfg.get("type") if client_type in ["web", "web_beta"]: self.updaters[name] = WebClientDeploy(cfg, self.cmd_helper) elif client_type in ["git_repo", "zip", "zip_beta"]: path = os.path.expanduser(cfg.get('path')) self.updaters[name] = get_deploy_class(path)( cfg, self.cmd_helper) else: raise config.error( f"Invalid type '{client_type}' for section [{section}]") self.cmd_request_lock = asyncio.Lock() self.initialized_lock = asyncio.Event() self.klippy_identified_evt: Optional[asyncio.Event] = None # Auto Status Refresh self.last_refresh_time: float = 0 self.refresh_cb: Optional[PeriodicCallback] = None if auto_refresh_enabled: self.refresh_cb = PeriodicCallback( self._handle_auto_refresh, # type: ignore UPDATE_REFRESH_INTERVAL_MS) self.server.register_endpoint( "/machine/update/moonraker", ["POST"], self._handle_update_request) self.server.register_endpoint( "/machine/update/klipper", ["POST"], self._handle_update_request) self.server.register_endpoint( "/machine/update/system", ["POST"], self._handle_update_request) self.server.register_endpoint( "/machine/update/client", ["POST"], self._handle_update_request) self.server.register_endpoint( "/machine/update/full", ["POST"], self._handle_full_update_request) self.server.register_endpoint( "/machine/update/status", ["GET"], self._handle_status_request) self.server.register_endpoint( "/machine/update/recover", ["POST"], self._handle_repo_recovery) self.server.register_notification("update_manager:update_response") self.server.register_notification("update_manager:update_refreshed") # Register Ready Event self.server.register_event_handler( "server:klippy_identified", self._set_klipper_repo) # Initialize GitHub API Rate Limits and configured updaters self.event_loop.register_callback( self._initalize_updaters, list(self.updaters.values()))
def test_prefix_sections(test_config: ConfigHelper): prefix = test_config.get_prefix_sections("prefix_sec") expected = ["prefix_sec one", "prefix_sec two", "prefix_sec three"] assert prefix == expected