power: add "locked_while_printing" option to avoid accidental shutdown
Signed-off-by: Jordan Ruthe <jordan.ruthe@gmail.com>
This commit is contained in:
parent
ff8e53b269
commit
b4602115d7
|
@ -164,6 +164,10 @@ initial_state: off
|
|||
# The initial state for GPIO type devices. May be on or
|
||||
# off. When moonraker starts the device will be set to this
|
||||
# state. Default is off.
|
||||
locked_while_printing: False
|
||||
# If True, locks the device so that the power cannot be changed while the
|
||||
# printer is printing. This is useful to avert an accidental shutdown to
|
||||
# the printer's power.
|
||||
address:
|
||||
port:
|
||||
# The above options are used for "tplink_smartplug" devices. The
|
||||
|
|
|
@ -60,6 +60,13 @@ class PrinterPower:
|
|||
IOLoop.current().spawn_callback(
|
||||
self._initalize_devices, list(self.devices.values()))
|
||||
|
||||
async def _check_klippy_printing(self):
|
||||
klippy_apis = self.server.lookup_plugin('klippy_apis')
|
||||
result = await klippy_apis.query_objects(
|
||||
{'print_stats': None}, default={})
|
||||
pstate = result.get('print_stats', {}).get('state', "").lower()
|
||||
return pstate == "printing"
|
||||
|
||||
async def _initalize_devices(self, inital_devs):
|
||||
for dev in inital_devs:
|
||||
ret = dev.initialize()
|
||||
|
@ -97,6 +104,14 @@ class PrinterPower:
|
|||
|
||||
async def _process_request(self, device, req):
|
||||
if req in ["on", "off"]:
|
||||
printing = await self._check_klippy_printing()
|
||||
logging.info("Device locked: %s" % device.get_locked_while_printing())
|
||||
logging.info("Klippy printing: %s" % printing)
|
||||
if device.get_locked_while_printing() and printing:
|
||||
self.server.error(f"Unable to change power for {device} " +
|
||||
"while printing")
|
||||
dev_info = device.get_device_info()
|
||||
return dev_info['status']
|
||||
ret = device.set_power(req)
|
||||
if asyncio.iscoroutine(ret):
|
||||
await ret
|
||||
|
@ -147,6 +162,28 @@ class PrinterPower:
|
|||
self.chip_factory.close()
|
||||
|
||||
|
||||
class PowerDevice:
|
||||
def __init__(self, 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.name = name_parts[1]
|
||||
self.state = "init"
|
||||
self.locked_while_printing = config.getboolean('locked_while_printing', False)
|
||||
self.off_when_shutdown = config.getboolean('off_when_shutdown', False)
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
def get_device_info(self):
|
||||
return {
|
||||
'device': self.name,
|
||||
'status': self.state
|
||||
}
|
||||
|
||||
def get_locked_while_printing(self):
|
||||
return self.locked_while_printing
|
||||
|
||||
class GpioChipFactory:
|
||||
def __init__(self):
|
||||
self.chips = {}
|
||||
|
@ -162,13 +199,9 @@ class GpioChipFactory:
|
|||
for chip in self.chips.values():
|
||||
chip.close()
|
||||
|
||||
class GpioDevice:
|
||||
class GpioDevice(PowerDevice):
|
||||
def __init__(self, config, chip_factory):
|
||||
name_parts = config.get_name().split(maxsplit=1)
|
||||
if len(name_parts) != 2:
|
||||
raise config.error(f"Invalid Section Name: {config.get_name()}")
|
||||
self.name = name_parts[1]
|
||||
self.state = "init"
|
||||
super().__init__(config)
|
||||
pin, chip_id, invert = self._parse_pin(config)
|
||||
try:
|
||||
chip = chip_factory.get_gpio_chip(chip_id)
|
||||
|
@ -186,7 +219,6 @@ class GpioDevice:
|
|||
f"Unable to init {pin}. Make sure the gpio is not in "
|
||||
"use by another program or exported by sysfs.")
|
||||
raise config.error("Power GPIO Config Error")
|
||||
self.off_when_shutdown = config.getboolean('off_when_shutdown', False)
|
||||
self.initial_state = config.getboolean('initial_state', False)
|
||||
|
||||
def _parse_pin(self, config):
|
||||
|
@ -214,13 +246,9 @@ class GpioDevice:
|
|||
def initialize(self):
|
||||
self.set_power("on" if self.initial_state else "off")
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
def get_device_info(self):
|
||||
return {
|
||||
'device': self.name,
|
||||
'status': self.state,
|
||||
**super().get_device_info(),
|
||||
'type': "gpio"
|
||||
}
|
||||
|
||||
|
@ -254,18 +282,13 @@ class GpioDevice:
|
|||
# https://github.com/softScheck/tplink-smartplug
|
||||
#
|
||||
# Copyright 2016 softScheck GmbH
|
||||
class TPLinkSmartPlug:
|
||||
class TPLinkSmartPlug(PowerDevice):
|
||||
START_KEY = 0xAB
|
||||
def __init__(self, config):
|
||||
super().__init__(config)
|
||||
self.server = config.get_server()
|
||||
self.addr = config.get("address")
|
||||
self.port = config.getint("port", 9999)
|
||||
self.off_when_shutdown = config.getboolean('off_when_shutdown', False)
|
||||
name_parts = config.get_name().split(maxsplit=1)
|
||||
if len(name_parts) != 2:
|
||||
raise config.error(f"Invalid Section Name: {config.get_name()}")
|
||||
self.name = name_parts[1]
|
||||
self.state = "init"
|
||||
|
||||
async def _send_tplink_command(self, command):
|
||||
out_cmd = {}
|
||||
|
@ -322,13 +345,9 @@ class TPLinkSmartPlug:
|
|||
async def initialize(self):
|
||||
await self.refresh_status()
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
def get_device_info(self):
|
||||
return {
|
||||
'device': self.name,
|
||||
'status': self.state,
|
||||
**super().get_device_info(),
|
||||
'type': "tplink_smartplug"
|
||||
}
|
||||
|
||||
|
@ -357,18 +376,12 @@ class TPLinkSmartPlug:
|
|||
self.state = state
|
||||
|
||||
|
||||
class Tasmota:
|
||||
class Tasmota(PowerDevice):
|
||||
def __init__(self, config):
|
||||
self.server = config.get_server()
|
||||
self.addr = config.get("address")
|
||||
self.output_id = config.getint("output_id", 1)
|
||||
self.password = config.get("password", "")
|
||||
self.off_when_shutdown = config.getboolean('off_when_shutdown', False)
|
||||
name_parts = config.get_name().split(maxsplit=1)
|
||||
if len(name_parts) != 2:
|
||||
raise config.error(f"Invalid Section Name: {config.get_name()}")
|
||||
self.name = name_parts[1]
|
||||
self.state = "init"
|
||||
|
||||
async def _send_tasmota_command(self, command, password=None):
|
||||
if command in ["on", "off"]:
|
||||
|
@ -394,13 +407,9 @@ class Tasmota:
|
|||
async def initialize(self):
|
||||
await self.refresh_status()
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
def get_device_info(self):
|
||||
return {
|
||||
'device': self.name,
|
||||
'status': self.state,
|
||||
**super().get_device_info(),
|
||||
'type': "tasmota"
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue