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
|
# The initial state for GPIO type devices. May be on or
|
||||||
# off. When moonraker starts the device will be set to this
|
# off. When moonraker starts the device will be set to this
|
||||||
# state. Default is off.
|
# 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:
|
address:
|
||||||
port:
|
port:
|
||||||
# The above options are used for "tplink_smartplug" devices. The
|
# The above options are used for "tplink_smartplug" devices. The
|
||||||
|
|
|
@ -60,6 +60,13 @@ class PrinterPower:
|
||||||
IOLoop.current().spawn_callback(
|
IOLoop.current().spawn_callback(
|
||||||
self._initalize_devices, list(self.devices.values()))
|
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):
|
async def _initalize_devices(self, inital_devs):
|
||||||
for dev in inital_devs:
|
for dev in inital_devs:
|
||||||
ret = dev.initialize()
|
ret = dev.initialize()
|
||||||
|
@ -97,6 +104,14 @@ class PrinterPower:
|
||||||
|
|
||||||
async def _process_request(self, device, req):
|
async def _process_request(self, device, req):
|
||||||
if req in ["on", "off"]:
|
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)
|
ret = device.set_power(req)
|
||||||
if asyncio.iscoroutine(ret):
|
if asyncio.iscoroutine(ret):
|
||||||
await ret
|
await ret
|
||||||
|
@ -147,6 +162,28 @@ class PrinterPower:
|
||||||
self.chip_factory.close()
|
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:
|
class GpioChipFactory:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.chips = {}
|
self.chips = {}
|
||||||
|
@ -162,13 +199,9 @@ class GpioChipFactory:
|
||||||
for chip in self.chips.values():
|
for chip in self.chips.values():
|
||||||
chip.close()
|
chip.close()
|
||||||
|
|
||||||
class GpioDevice:
|
class GpioDevice(PowerDevice):
|
||||||
def __init__(self, config, chip_factory):
|
def __init__(self, config, chip_factory):
|
||||||
name_parts = config.get_name().split(maxsplit=1)
|
super().__init__(config)
|
||||||
if len(name_parts) != 2:
|
|
||||||
raise config.error(f"Invalid Section Name: {config.get_name()}")
|
|
||||||
self.name = name_parts[1]
|
|
||||||
self.state = "init"
|
|
||||||
pin, chip_id, invert = self._parse_pin(config)
|
pin, chip_id, invert = self._parse_pin(config)
|
||||||
try:
|
try:
|
||||||
chip = chip_factory.get_gpio_chip(chip_id)
|
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 "
|
f"Unable to init {pin}. Make sure the gpio is not in "
|
||||||
"use by another program or exported by sysfs.")
|
"use by another program or exported by sysfs.")
|
||||||
raise config.error("Power GPIO Config Error")
|
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)
|
self.initial_state = config.getboolean('initial_state', False)
|
||||||
|
|
||||||
def _parse_pin(self, config):
|
def _parse_pin(self, config):
|
||||||
|
@ -214,13 +246,9 @@ class GpioDevice:
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.set_power("on" if self.initial_state else "off")
|
self.set_power("on" if self.initial_state else "off")
|
||||||
|
|
||||||
def get_name(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_device_info(self):
|
def get_device_info(self):
|
||||||
return {
|
return {
|
||||||
'device': self.name,
|
**super().get_device_info(),
|
||||||
'status': self.state,
|
|
||||||
'type': "gpio"
|
'type': "gpio"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,18 +282,13 @@ class GpioDevice:
|
||||||
# https://github.com/softScheck/tplink-smartplug
|
# https://github.com/softScheck/tplink-smartplug
|
||||||
#
|
#
|
||||||
# Copyright 2016 softScheck GmbH
|
# Copyright 2016 softScheck GmbH
|
||||||
class TPLinkSmartPlug:
|
class TPLinkSmartPlug(PowerDevice):
|
||||||
START_KEY = 0xAB
|
START_KEY = 0xAB
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
|
super().__init__(config)
|
||||||
self.server = config.get_server()
|
self.server = config.get_server()
|
||||||
self.addr = config.get("address")
|
self.addr = config.get("address")
|
||||||
self.port = config.getint("port", 9999)
|
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):
|
async def _send_tplink_command(self, command):
|
||||||
out_cmd = {}
|
out_cmd = {}
|
||||||
|
@ -322,13 +345,9 @@ class TPLinkSmartPlug:
|
||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
await self.refresh_status()
|
await self.refresh_status()
|
||||||
|
|
||||||
def get_name(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_device_info(self):
|
def get_device_info(self):
|
||||||
return {
|
return {
|
||||||
'device': self.name,
|
**super().get_device_info(),
|
||||||
'status': self.state,
|
|
||||||
'type': "tplink_smartplug"
|
'type': "tplink_smartplug"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,18 +376,12 @@ class TPLinkSmartPlug:
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
|
|
||||||
class Tasmota:
|
class Tasmota(PowerDevice):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
self.server = config.get_server()
|
self.server = config.get_server()
|
||||||
self.addr = config.get("address")
|
self.addr = config.get("address")
|
||||||
self.output_id = config.getint("output_id", 1)
|
self.output_id = config.getint("output_id", 1)
|
||||||
self.password = config.get("password", "")
|
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):
|
async def _send_tasmota_command(self, command, password=None):
|
||||||
if command in ["on", "off"]:
|
if command in ["on", "off"]:
|
||||||
|
@ -394,13 +407,9 @@ class Tasmota:
|
||||||
async def initialize(self):
|
async def initialize(self):
|
||||||
await self.refresh_status()
|
await self.refresh_status()
|
||||||
|
|
||||||
def get_name(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_device_info(self):
|
def get_device_info(self):
|
||||||
return {
|
return {
|
||||||
'device': self.name,
|
**super().get_device_info(),
|
||||||
'status': self.state,
|
|
||||||
'type': "tasmota"
|
'type': "tasmota"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue