power: refactor initialization

The entire configuration should be validated prior to device initialization.  In the event of an error, the GPIO Chip factory must be closed.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Arksine 2021-01-06 14:39:33 -05:00
parent e0f4b46364
commit 5f986ab770
1 changed files with 30 additions and 22 deletions

View File

@ -20,6 +20,27 @@ from tornado.escape import json_decode
class PrinterPower: class PrinterPower:
def __init__(self, config): def __init__(self, config):
self.server = config.get_server() self.server = config.get_server()
self.chip_factory = GpioChipFactory()
self.devices = {}
prefix_sections = config.get_prefix_sections("power")
logging.info(f"Power plugin loading devices: {prefix_sections}")
try:
for section in prefix_sections:
cfg = config[section]
dev_type = cfg.get("type")
if dev_type == "gpio":
dev = GpioDevice(cfg, self.chip_factory)
elif dev_type == "tplink_smartplug":
dev = TPLinkSmartPlug(cfg)
elif dev_type == "tasmota":
dev = Tasmota(cfg)
else:
raise config.error(f"Unsupported Device Type: {dev_type}")
self.devices[dev.get_name()] = dev
except Exception:
self.chip_factory.close()
raise
self.server.register_endpoint( self.server.register_endpoint(
"/machine/device_power/devices", ['GET'], "/machine/device_power/devices", ['GET'],
self._handle_list_devices) self._handle_list_devices)
@ -36,24 +57,14 @@ class PrinterPower:
"set_device_power", self.set_device_power) "set_device_power", self.set_device_power)
self.server.register_event_handler( self.server.register_event_handler(
"server:klippy_shutdown", self._handle_klippy_shutdown) "server:klippy_shutdown", self._handle_klippy_shutdown)
IOLoop.current().spawn_callback(
self._initalize_devices, list(self.devices.values()))
self.chip_factory = GpioChipFactory() async def _initalize_devices(self, inital_devs):
self.current_dev = None for dev in inital_devs:
self.devices = {} ret = dev.initialize()
prefix_sections = config.get_prefix_sections("power") if asyncio.iscoroutine(ret):
logging.info(f"Power plugin loading devices: {prefix_sections}") await ret
for section in prefix_sections:
cfg = config[section]
dev_type = cfg.get("type")
if dev_type == "gpio":
dev = GpioDevice(cfg, self.chip_factory)
elif dev_type == "tplink_smartplug":
dev = TPLinkSmartPlug(cfg)
elif dev_type == "tasmota":
dev = Tasmota(cfg)
else:
raise config.error(f"Unsupported Device Type: {dev_type}")
self.devices[dev.get_name()] = dev
async def _handle_klippy_shutdown(self): async def _handle_klippy_shutdown(self):
for name, dev in self.devices.items(): for name, dev in self.devices.items():
@ -176,8 +187,7 @@ class GpioDevice:
"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.off_when_shutdown = config.getboolean('off_when_shutdown', False)
initial_state = config.getboolean('initial_state', False) self.initial_state = config.getboolean('initial_state', False)
self.set_power("on" if initial_state else "off")
def _parse_pin(self, config): def _parse_pin(self, config):
pin = cfg_pin = config.get("pin") pin = cfg_pin = config.get("pin")
@ -202,7 +212,7 @@ class GpioDevice:
return pin, chip_id, invert return pin, chip_id, invert
def initialize(self): def initialize(self):
pass self.set_power("on" if self.initial_state else "off")
def get_name(self): def get_name(self):
return self.name return self.name
@ -256,7 +266,6 @@ class TPLinkSmartPlug:
raise config.error(f"Invalid Section Name: {config.get_name()}") raise config.error(f"Invalid Section Name: {config.get_name()}")
self.name = name_parts[1] self.name = name_parts[1]
self.state = "init" self.state = "init"
IOLoop.current().spawn_callback(self.initialize)
async def _send_tplink_command(self, command): async def _send_tplink_command(self, command):
out_cmd = {} out_cmd = {}
@ -360,7 +369,6 @@ class Tasmota:
raise config.error(f"Invalid Section Name: {config.get_name()}") raise config.error(f"Invalid Section Name: {config.get_name()}")
self.name = name_parts[1] self.name = name_parts[1]
self.state = "init" self.state = "init"
IOLoop.current().spawn_callback(self.initialize)
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"]: