klippy_connection: track connection state with an enum
Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
b18e9cc222
commit
7de61eb113
@ -28,7 +28,8 @@ from .common import (
|
||||
APIDefinition,
|
||||
APITransport,
|
||||
TransportType,
|
||||
RequestType
|
||||
RequestType,
|
||||
KlippyState
|
||||
)
|
||||
from .utils import json_wrapper as jsonw
|
||||
from .websockets import (
|
||||
@ -1133,11 +1134,10 @@ class WelcomeHandler(tornado.web.RequestHandler):
|
||||
"The [authorization] section in moonraker.conf must be "
|
||||
"configured to enable CORS."
|
||||
)
|
||||
kstate = self.server.get_klippy_state()
|
||||
if kstate != "disconnected":
|
||||
kinfo = self.server.get_klippy_info()
|
||||
kmsg = kinfo.get("state_message", kstate)
|
||||
summary.append(f"Klipper reports {kmsg.lower()}")
|
||||
kconn: Klippy = self.server.lookup_component("klippy_connection")
|
||||
kstate = kconn.state
|
||||
if kstate != KlippyState.DISCONNECTED:
|
||||
summary.append(f"Klipper reports {kstate.message.lower()}")
|
||||
else:
|
||||
summary.append(
|
||||
"Moonraker is not currently connected to Klipper. Make sure "
|
||||
|
@ -123,6 +123,37 @@ class JobEvent(ExtendedEnum):
|
||||
def is_printing(self) -> bool:
|
||||
return self.value in [2, 4]
|
||||
|
||||
class KlippyState(ExtendedEnum):
|
||||
DISCONNECTED = 1
|
||||
STARTUP = 2
|
||||
READY = 3
|
||||
ERROR = 4
|
||||
SHUTDOWN = 5
|
||||
|
||||
@classmethod
|
||||
def from_string(cls, enum_name: str, msg: str = ""):
|
||||
str_name = enum_name.upper()
|
||||
for name, member in cls.__members__.items():
|
||||
if name == str_name:
|
||||
instance = cls(member.value)
|
||||
if msg:
|
||||
instance.set_message(msg)
|
||||
return instance
|
||||
raise ValueError(f"No enum member named {enum_name}")
|
||||
|
||||
|
||||
def set_message(self, msg: str) -> None:
|
||||
self._state_message: str = msg
|
||||
|
||||
@property
|
||||
def message(self) -> str:
|
||||
if hasattr(self, "_state_message"):
|
||||
return self._state_message
|
||||
return ""
|
||||
|
||||
def startup_complete(self) -> bool:
|
||||
return self.value > 2
|
||||
|
||||
class Subscribable:
|
||||
def send_status(
|
||||
self, status: Dict[str, Any], eventtime: float
|
||||
|
@ -15,7 +15,7 @@ from typing import (
|
||||
Dict,
|
||||
List,
|
||||
)
|
||||
from ..common import JobEvent
|
||||
from ..common import JobEvent, KlippyState
|
||||
if TYPE_CHECKING:
|
||||
from ..confighelper import ConfigHelper
|
||||
from .klippy_apis import KlippyAPI
|
||||
@ -27,8 +27,8 @@ class JobState:
|
||||
self.server.register_event_handler(
|
||||
"server:klippy_started", self._handle_started)
|
||||
|
||||
async def _handle_started(self, state: str) -> None:
|
||||
if state != "ready":
|
||||
async def _handle_started(self, state: KlippyState) -> None:
|
||||
if state != KlippyState.READY:
|
||||
return
|
||||
kapis: KlippyAPI = self.server.lookup_component('klippy_apis')
|
||||
sub: Dict[str, Optional[List[str]]] = {"print_stats": None}
|
||||
|
@ -18,7 +18,8 @@ from ..common import (
|
||||
Subscribable,
|
||||
WebRequest,
|
||||
APITransport,
|
||||
JsonRPC
|
||||
JsonRPC,
|
||||
KlippyState
|
||||
)
|
||||
from ..utils import json_wrapper as jsonw
|
||||
|
||||
@ -372,7 +373,7 @@ class MQTTClient(APITransport, Subscribable):
|
||||
self._do_reconnect(first=True)
|
||||
)
|
||||
|
||||
async def _handle_klippy_started(self, state: str) -> None:
|
||||
async def _handle_klippy_started(self, state: KlippyState) -> None:
|
||||
if self.status_objs:
|
||||
args = {'objects': self.status_objs}
|
||||
try:
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from ..common import RequestType, TransportType
|
||||
from ..common import RequestType, TransportType, KlippyState
|
||||
|
||||
# Annotation imports
|
||||
from typing import (
|
||||
@ -16,6 +16,7 @@ from typing import (
|
||||
List,
|
||||
)
|
||||
if TYPE_CHECKING:
|
||||
from ..klippy_connection import KlippyConnection
|
||||
from ..confighelper import ConfigHelper
|
||||
from ..common import WebRequest
|
||||
from .klippy_apis import KlippyAPI as APIComp
|
||||
@ -153,10 +154,11 @@ class OctoPrintCompat:
|
||||
data.update(status[heater_name])
|
||||
|
||||
def printer_state(self) -> str:
|
||||
klippy_state = self.server.get_klippy_state()
|
||||
if klippy_state in ["disconnected", "startup"]:
|
||||
kconn: KlippyConnection = self.server.lookup_component("klippy_connection")
|
||||
klippy_state = kconn.state
|
||||
if not klippy_state.startup_complete():
|
||||
return 'Offline'
|
||||
elif klippy_state != 'ready':
|
||||
elif klippy_state != KlippyState.READY:
|
||||
return 'Error'
|
||||
return {
|
||||
'standby': 'Operational',
|
||||
@ -202,11 +204,11 @@ class OctoPrintCompat:
|
||||
"""
|
||||
Server status
|
||||
"""
|
||||
klippy_state = self.server.get_klippy_state()
|
||||
kconn: KlippyConnection = self.server.lookup_component("klippy_connection")
|
||||
klippy_state = kconn.state
|
||||
return {
|
||||
'server': OCTO_VERSION,
|
||||
'safemode': (
|
||||
None if klippy_state == 'ready' else 'settings')
|
||||
'safemode': None if klippy_state == KlippyState.READY else 'settings'
|
||||
}
|
||||
|
||||
async def _post_login_user(self,
|
||||
|
@ -12,7 +12,7 @@ import asyncio
|
||||
import time
|
||||
from urllib.parse import quote, urlencode
|
||||
from ..utils import json_wrapper as jsonw
|
||||
from ..common import RequestType
|
||||
from ..common import RequestType, KlippyState
|
||||
|
||||
# Annotation imports
|
||||
from typing import (
|
||||
@ -262,11 +262,11 @@ class PowerDevice:
|
||||
'initial_state', None
|
||||
)
|
||||
|
||||
def _schedule_firmware_restart(self, state: str = "") -> None:
|
||||
def _schedule_firmware_restart(self, state: KlippyState) -> None:
|
||||
if not self.need_scheduled_restart:
|
||||
return
|
||||
self.need_scheduled_restart = False
|
||||
if state == "ready":
|
||||
if state == KlippyState.READY:
|
||||
logging.info(
|
||||
f"Power Device {self.name}: Klipper reports 'ready', "
|
||||
"aborting FIRMWARE_RESTART"
|
||||
@ -304,8 +304,9 @@ class PowerDevice:
|
||||
await self.process_bound_services()
|
||||
if self.state == "on" and self.klipper_restart:
|
||||
self.need_scheduled_restart = True
|
||||
klippy_state = self.server.get_klippy_state()
|
||||
if klippy_state in ["disconnected", "startup"]:
|
||||
kconn: KlippyConnection = self.server.lookup_component("klippy_connection")
|
||||
klippy_state = kconn.state
|
||||
if not klippy_state.startup_complete():
|
||||
# If klippy is currently disconnected or hasn't proceeded past
|
||||
# the startup state, schedule the restart in the
|
||||
# "klippy_started" event callback.
|
||||
@ -338,7 +339,8 @@ class PowerDevice:
|
||||
self.off_when_shutdown_delay, self._power_off_on_shutdown)
|
||||
|
||||
def _power_off_on_shutdown(self) -> None:
|
||||
if self.server.get_klippy_state() != "shutdown":
|
||||
kconn: KlippyConnection = self.server.lookup_component("klippy_connection")
|
||||
if kconn.state != KlippyState.SHUTDOWN:
|
||||
return
|
||||
logging.info(
|
||||
f"Powering off device '{self.name}' due to klippy shutdown")
|
||||
|
@ -17,7 +17,7 @@ import logging.handlers
|
||||
import tempfile
|
||||
from queue import SimpleQueue
|
||||
from ..loghelper import LocalQueueHandler
|
||||
from ..common import Subscribable, WebRequest, JobEvent
|
||||
from ..common import Subscribable, WebRequest, JobEvent, KlippyState
|
||||
from ..utils import json_wrapper as jsonw
|
||||
|
||||
from typing import (
|
||||
@ -640,12 +640,12 @@ class SimplyPrint(Subscribable):
|
||||
self.cache.firmware_info.update(ui_data)
|
||||
self.send_sp("machine_data", ui_data)
|
||||
|
||||
def _on_klippy_startup(self, state: str) -> None:
|
||||
if state != "ready":
|
||||
def _on_klippy_startup(self, state: KlippyState) -> None:
|
||||
if state != KlippyState.READY:
|
||||
self._update_state("error")
|
||||
kconn: KlippyConnection
|
||||
kconn = self.server.lookup_component("klippy_connection")
|
||||
self.send_sp("printer_error", {"error": kconn.state_message})
|
||||
self.send_sp("printer_error", {"error": kconn.state.message})
|
||||
self.send_sp("connection", {"new": "connected"})
|
||||
self._send_firmware_data()
|
||||
|
||||
@ -653,7 +653,7 @@ class SimplyPrint(Subscribable):
|
||||
self._update_state("error")
|
||||
kconn: KlippyConnection
|
||||
kconn = self.server.lookup_component("klippy_connection")
|
||||
self.send_sp("printer_error", {"error": kconn.state_message})
|
||||
self.send_sp("printer_error", {"error": kconn.state.message})
|
||||
|
||||
def _on_klippy_disconnected(self) -> None:
|
||||
self._update_state("offline")
|
||||
@ -927,10 +927,11 @@ class SimplyPrint(Subscribable):
|
||||
self.send_sp("temps", temp_data)
|
||||
|
||||
def _update_state_from_klippy(self) -> None:
|
||||
kstate = self.server.get_klippy_state()
|
||||
if kstate == "ready":
|
||||
kconn: KlippyConnection = self.server.lookup_component("klippy_connection")
|
||||
klippy_state = kconn.state
|
||||
if klippy_state == KlippyState.READY:
|
||||
sp_state = "operational"
|
||||
elif kstate in ["error", "shutdown"]:
|
||||
elif klippy_state in [KlippyState.ERROR, KlippyState.SHUTDOWN]:
|
||||
sp_state = "error"
|
||||
else:
|
||||
sp_state = "offline"
|
||||
@ -1613,7 +1614,8 @@ class PrintHandler:
|
||||
self.simplyprint.send_sp("file_progress", data)
|
||||
|
||||
async def _check_can_print(self) -> bool:
|
||||
if self.server.get_klippy_state() != "ready":
|
||||
kconn: KlippyConnection = self.server.lookup_component("klippy_connection")
|
||||
if kconn.state != KlippyState.READY:
|
||||
return False
|
||||
kapi: KlippyAPI = self.server.lookup_component("klippy_apis")
|
||||
try:
|
||||
|
@ -14,6 +14,7 @@ import asyncio
|
||||
import pathlib
|
||||
from .utils import ServerError, get_unix_peer_credentials
|
||||
from .utils import json_wrapper as jsonw
|
||||
from .common import KlippyState
|
||||
|
||||
# Annotation imports
|
||||
from typing import (
|
||||
@ -78,8 +79,8 @@ class KlippyConnection:
|
||||
self._peer_cred: Dict[str, int] = {}
|
||||
self._service_info: Dict[str, Any] = {}
|
||||
self.init_attempts: int = 0
|
||||
self._state: str = "disconnected"
|
||||
self._state_message: str = "Klippy Disconnected"
|
||||
self._state: KlippyState = KlippyState.DISCONNECTED
|
||||
self._state.set_message("Klippy Disconnected")
|
||||
self.subscriptions: Dict[Subscribable, Subscription] = {}
|
||||
self.subscription_cache: Dict[str, Dict[str, Any]] = {}
|
||||
# Setup remote methods accessable to Klippy. Note that all
|
||||
@ -106,14 +107,14 @@ class KlippyConnection:
|
||||
return self.server.lookup_component("klippy_apis")
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
def state(self) -> KlippyState:
|
||||
if self.is_connected() and not self._klippy_started:
|
||||
return "startup"
|
||||
return KlippyState.STARTUP
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def state_message(self) -> str:
|
||||
return self._state_message
|
||||
return self._state.message
|
||||
|
||||
@property
|
||||
def klippy_info(self) -> Dict[str, Any]:
|
||||
@ -241,7 +242,7 @@ class KlippyConnection:
|
||||
connection.call_method(method_name, kwargs)
|
||||
self.remote_methods[method_name] = _on_agent_method_received
|
||||
self.klippy_reg_methods.append(method_name)
|
||||
if self._methods_registered and self._state != "disconnected":
|
||||
if self._methods_registered and self._state != KlippyState.DISCONNECTED:
|
||||
coro = self.klippy_apis.register_method(method_name)
|
||||
return self.event_loop.create_task(coro)
|
||||
return None
|
||||
@ -331,7 +332,7 @@ class KlippyConnection:
|
||||
self._methods_registered = False
|
||||
self._missing_reqs.clear()
|
||||
self.init_attempts = 0
|
||||
self._state = "startup"
|
||||
self._state = KlippyState.STARTUP
|
||||
while self.server.is_running():
|
||||
await asyncio.sleep(INIT_TIME)
|
||||
await self._check_ready()
|
||||
@ -391,8 +392,10 @@ class KlippyConnection:
|
||||
msg = f"Klipper Version: {version}"
|
||||
self.server.add_log_rollover_item("klipper_version", msg)
|
||||
self._klippy_info = dict(result)
|
||||
state_message: str = self._state.message
|
||||
if "state_message" in self._klippy_info:
|
||||
self._state_message = self._klippy_info["state_message"]
|
||||
state_message = self._klippy_info["state_message"]
|
||||
self._state.set_message(state_message)
|
||||
if "state" not in result:
|
||||
return
|
||||
if send_id:
|
||||
@ -400,19 +403,20 @@ class KlippyConnection:
|
||||
await self.server.send_event("server:klippy_identified")
|
||||
# Request initial endpoints to register info, emergency stop APIs
|
||||
await self._request_endpoints()
|
||||
self._state = result["state"]
|
||||
if self._state != "startup":
|
||||
self._state = KlippyState.from_string(result["state"], state_message)
|
||||
if self._state != KlippyState.STARTUP:
|
||||
await self._request_initial_subscriptions()
|
||||
# Register remaining endpoints available
|
||||
await self._request_endpoints()
|
||||
startup_state = self._state
|
||||
await self.server.send_event(
|
||||
"server:klippy_started", startup_state
|
||||
)
|
||||
await self.server.send_event("server:klippy_started", startup_state)
|
||||
self._klippy_started = True
|
||||
if self._state != "ready":
|
||||
logging.info("\n" + self._state_message)
|
||||
if self._state == "shutdown" and startup_state != "shutdown":
|
||||
if self._state != KlippyState.READY:
|
||||
logging.info("\n" + self._state.message)
|
||||
if (
|
||||
self._state == KlippyState.SHUTDOWN and
|
||||
startup_state != KlippyState.SHUTDOWN
|
||||
):
|
||||
# Klippy shutdown during startup event
|
||||
self.server.send_event("server:klippy_shutdown")
|
||||
else:
|
||||
@ -425,10 +429,10 @@ class KlippyConnection:
|
||||
logging.exception(
|
||||
f"Unable to register method '{method}'")
|
||||
self._methods_registered = True
|
||||
if self._state == "ready":
|
||||
if self._state == KlippyState.READY:
|
||||
logging.info("Klippy ready")
|
||||
await self.server.send_event("server:klippy_ready")
|
||||
if self._state == "shutdown":
|
||||
if self._state == KlippyState.SHUTDOWN:
|
||||
# Klippy shutdown during ready event
|
||||
self.server.send_event("server:klippy_shutdown")
|
||||
else:
|
||||
@ -520,21 +524,23 @@ class KlippyConnection:
|
||||
self.subscription_cache.setdefault(field, {}).update(item)
|
||||
if 'webhooks' in status:
|
||||
wh: Dict[str, str] = status['webhooks']
|
||||
state_message: str = self._state.message
|
||||
if "state_message" in wh:
|
||||
self._state_message = wh["state_message"]
|
||||
state_message = wh["state_message"]
|
||||
self._state.set_message(state_message)
|
||||
# XXX - process other states (startup, ready, error, etc)?
|
||||
if "state" in wh:
|
||||
state = wh["state"]
|
||||
new_state = KlippyState.from_string(wh["state"], state_message)
|
||||
if (
|
||||
state == "shutdown" and
|
||||
new_state == KlippyState.SHUTDOWN and
|
||||
not self._klippy_initializing and
|
||||
self._state != "shutdown"
|
||||
self._state != KlippyState.SHUTDOWN
|
||||
):
|
||||
# If the shutdown state is received during initialization
|
||||
# defer the event, the init routine will handle it.
|
||||
logging.info("Klippy has shutdown")
|
||||
self.server.send_event("server:klippy_shutdown")
|
||||
self._state = state
|
||||
self._state = new_state
|
||||
for conn, sub in self.subscriptions.items():
|
||||
conn_status: Dict[str, Any] = {}
|
||||
for name, fields in sub.items():
|
||||
@ -657,7 +663,7 @@ class KlippyConnection:
|
||||
return self.writer is not None and not self.closing
|
||||
|
||||
def is_ready(self) -> bool:
|
||||
return self._state == "ready"
|
||||
return self._state == KlippyState.READY
|
||||
|
||||
def is_printing(self) -> bool:
|
||||
if not self.is_ready():
|
||||
@ -705,8 +711,8 @@ class KlippyConnection:
|
||||
self._klippy_initializing = False
|
||||
self._klippy_started = False
|
||||
self._methods_registered = False
|
||||
self._state = "disconnected"
|
||||
self._state_message = "Klippy Disconnected"
|
||||
self._state = KlippyState.DISCONNECTED
|
||||
self._state.set_message("Klippy Disconnected")
|
||||
for request in self.pending_requests.values():
|
||||
request.set_exception(ServerError("Klippy Disconnected", 503))
|
||||
self.pending_requests = {}
|
||||
|
@ -368,9 +368,6 @@ class Server:
|
||||
def get_klippy_info(self) -> Dict[str, Any]:
|
||||
return self.klippy_connection.klippy_info
|
||||
|
||||
def get_klippy_state(self) -> str:
|
||||
return self.klippy_connection.state
|
||||
|
||||
def _handle_term_signal(self) -> None:
|
||||
logging.info("Exiting with signal SIGTERM")
|
||||
self.event_loop.register_callback(self._stop_server, "terminate")
|
||||
@ -447,7 +444,7 @@ class Server:
|
||||
]
|
||||
return {
|
||||
'klippy_connected': self.klippy_connection.is_connected(),
|
||||
'klippy_state': self.klippy_connection.state,
|
||||
'klippy_state': str(self.klippy_connection.state),
|
||||
'components': list(self.components.keys()),
|
||||
'failed_components': self.failed_components,
|
||||
'registered_directories': reg_dirs,
|
||||
|
Loading…
x
Reference in New Issue
Block a user