Repository: boneIO-eu/app_black (language: python)

Issue:
Prepare for pdm with pep582
Prepare for pdm with pep582


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/publish-to-pypi.yaml b/.github/workflows/publish-to-pypi.yaml
index 04b5720..de73393 100644
--- a/.github/workflows/publish-to-pypi.yaml
+++ b/.github/workflows/publish-to-pypi.yaml
@@ -7,6 +7,7 @@ on:
     branches:
       - 'master'
       - 'main'
+      - 'dev'
     paths:
       - '**.py'
   pull_request:
@@ -28,31 +29,29 @@ on:
 jobs:
   build-n-publish:
     name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI
-    runs-on: ubuntu-18.04
+    runs-on: ubuntu-latest
     steps:
     - uses: actions/checkout@master
-    - name: Set up Python 3.7
-      uses: actions/setup-python@v1
+    - uses: pdm-project/setup-pdm@v2.6
+      name: Setup Python and PDM
       with:
         python-version: 3.7
-    - name: Install pypa/build
-      run: >-
-        python -m
-        pip install
-        build
-        --user
-    - name: Build a binary wheel and a source tarball
-      run: >-
-        python -m
-        build
-        --sdist
-        --wheel
-        --outdir dist/
-        .
-    - name: Publish distribution 📦 to PyPI
+        architecture: x64
+        version: 1.15.3
+        enable-pep582: true # Enable PEP 582 package loading globally
+    - name: Install dependencies
+      run: |
+        python -m pip install -U twine
+    - name: Build
+      run: |
+        pdm build
+    - name: Publish package
       if: startsWith(github.ref, 'refs/tags') || startsWith(github.event.inputs.tags, 'Deploy')
-      uses: pypa/gh-action-pypi-publish@master
-      with:
-        password: ${{ secrets.PYPI_API_TOKEN }}
-        skip_existing: true
-
+      run: |
+        pdm plugin add pdm-publish
+        pdm publish --password ${{ secrets.PYPI_API_TOKEN }}
+    # - name: Publish distribution 📦 to PyPI
+    #   uses: pypa/gh-action-pypi-publish@master
+    #   with:
+    #     password: ${{ secrets.PYPI_API_TOKEN }}
+    #     skip_existing: true
diff --git a/.pdm.toml b/.pdm.toml
new file mode 100644
index 0000000..b5176a8
--- /dev/null
+++ b/.pdm.toml
@@ -0,0 +1,2 @@
+[python]
+path = "/usr/bin/python3"
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..ed6d3c2
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,32 @@
+# See https://pre-commit.com for more information
+# See https://pre-commit.com/hooks.html for more hooks
+repos:
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v4.3.0
+    hooks:
+      - id: trailing-whitespace
+      - id: end-of-file-fixer
+      - id: check-added-large-files
+  - repo: https://github.com/psf/black
+    rev: 22.3.0
+    hooks:
+      - id: black
+
+  - repo: https://github.com/PyCQA/flake8
+    rev: 4.0.1
+    hooks:
+      - id: flake8
+  - repo: https://github.com/PyCQA/bandit
+    rev: 1.7.4
+    hooks:
+      - id: bandit
+        args:
+          - --quiet
+          - --format=custom
+          - --configfile=tests/bandit.yaml
+        files: ^(boneio)/.+\.py$
+
+  - repo: https://github.com/pycqa/isort
+    rev: 5.10.1
+    hooks:
+      - id: isort
diff --git a/boneio/bonecli.py b/boneio/bonecli.py
index 80e5024..4b350fa 100644
--- a/boneio/bonecli.py
+++ b/boneio/bonecli.py
@@ -5,6 +5,7 @@
 import sys
 
 from colorlog import ColoredFormatter
+from yaml import MarkedYAMLError
 
 from boneio.const import ACTION
 from boneio.helper import load_config_from_file
@@ -12,7 +13,6 @@
 from boneio.helper.logger import configure_logger
 from boneio.runner import async_run
 from boneio.version import __version__
-from yaml import MarkedYAMLError
 
 TASK_CANCELATION_TIMEOUT = 1
 
diff --git a/boneio/const.py b/boneio/const.py
index 5db8ffc..7733465 100644
--- a/boneio/const.py
+++ b/boneio/const.py
@@ -1,8 +1,6 @@
 # from typing import Literal
-from datetime import timedelta
-
 try:
-    from Adafruit_BBIO.GPIO import HIGH, LOW, BOTH, FALLING, RISING
+    from Adafruit_BBIO.GPIO import BOTH, FALLING, HIGH, LOW, RISING
 except ModuleNotFoundError:
     HIGH = "high"
     LOW = "low"
@@ -54,6 +52,7 @@
     "uart5": {ID: "/dev/ttyS5", TX: "P8.37", RX: "P8.38"},
 }
 
+relay_actions = {ON: "turn_on", OFF: "turn_off", "TOGGLE": "toggle"}
 
 # HA CONSTS
 HOMEASSISTANT = "homeassistant"
diff --git a/boneio/cover.py b/boneio/cover.py
index f722210..b771b08 100644
--- a/boneio/cover.py
+++ b/boneio/cover.py
@@ -2,7 +2,8 @@
 import asyncio
 import logging
 from typing import Callable
-from boneio.const import CLOSE, COVER, IDLE, OPEN, OPENING, CLOSING, CLOSED, STOP
+
+from boneio.const import CLOSE, CLOSED, CLOSING, COVER, IDLE, OPEN, OPENING, STOP
 from boneio.helper.events import EventBus
 from boneio.helper.mqtt import BasicMqtt
 from boneio.helper.timeperiod import TimePeriod
diff --git a/boneio/example_config/output24x16A.yaml b/boneio/example_config/output24x16A.yaml
index cb0a216..b953dde 100644
--- a/boneio/example_config/output24x16A.yaml
+++ b/boneio/example_config/output24x16A.yaml
@@ -88,7 +88,7 @@
   mcp_id: mcp2
   pin: 0
   output_type: light
-- id: OUT_19 
+- id: OUT_19
   kind: mcp
   mcp_id: mcp2
   pin: 1
@@ -117,4 +117,4 @@
   kind: mcp
   mcp_id: mcp1
   pin: 10
-  output_type: light
\ No newline at end of file
+  output_type: light
diff --git a/boneio/example_config/output32x5A.yaml b/boneio/example_config/output32x5A.yaml
index 812da01..73be990 100644
--- a/boneio/example_config/output32x5A.yaml
+++ b/boneio/example_config/output32x5A.yaml
@@ -1,198 +1,197 @@
 # mcp1 - upper left 8 relays
 - id: OUT_01
- kind: mcp
- mcp_id: mcp1
- pin: 0
- output_type: light
-  
+  kind: mcp
+  mcp_id: mcp1
+  pin: 0
+  output_type: light
+
 - id: OUT_02
   kind: mcp
   mcp_id: mcp1
   pin: 1
   output_type: light
-  
+
 - id: OUT_03
- kind: mcp
- mcp_id: mcp1
- pin: 2
- output_type: light
-  
+  kind: mcp
+  mcp_id: mcp1
+  pin: 2
+  output_type: light
+
 - id: OUT_04
   kind: mcp
   mcp_id: mcp1
   pin: 3
   output_type: light
-  
+
 - id: OUT_05
   kind: mcp
   mcp_id: mcp1
   pin: 4
   output_type: light
-  
+
 - id: OUT_06
   kind: mcp
   mcp_id: mcp1
   pin: 5
   output_type: light
-  
+
 - id: OUT_07
- kind: mcp
- mcp_id: mcp1
- pin: 6
- output_type: light
-  
+  kind: mcp
+  mcp_id: mcp1
+  pin: 6
+  output_type: light
+
 - id: OUT_08
   kind: mcp
   mcp_id: mcp1
   pin: 7
   output_type: light
-  
-  
+
+
 # mcp2 - upper right 8 relays
 - id: OUT_09
   kind: mcp
   mcp_id: mcp2
   pin: 0
   output_type: light
-  
+
 - id: OUT_10
   kind: mcp
   mcp_id: mcp2
   pin: 1
   output_type: light
-  
+
 - id: OUT_11
   kind: mcp
   mcp_id: mcp2
   pin: 2
   output_type: light
-  
+
 - id: OUT_12
   kind: mcp
   mcp_id: mcp2
   pin: 3
   output_type: light
-  
+
 - id: OUT_13
- kind: mcp
- mcp_id: mcp2
- pin: 4
- output_type: light
-  
+  kind: mcp
+  mcp_id: mcp2
+  pin: 4
+  output_type: light
+
 - id: OUT_14
   kind: mcp
   mcp_id: mcp2
   pin: 5
   output_type: light
-  
+
 - id: OUT_15
- kind: mcp
- mcp_id: mcp2
- pin: 6
- output_type: light
-  
+  kind: mcp
+  mcp_id: mcp2
+  pin: 6
+  output_type: light
+
 - id: OUT_16
- kind: mcp
- mcp_id: mcp2
- pin: 7
- output_type: light
-  
-  
+  kind: mcp
+  mcp_id: mcp2
+  pin: 7
+  output_type: light
+
 # mcp1 - lower left 8 relays
 - id: OUT_17
   kind: mcp
   mcp_id: mcp1
   pin: 15
   output_type: light
-  
+
 - id: OUT_18
   kind: mcp
   mcp_id: mcp1
   pin: 14
   output_type: light
-  
+
 - id: OUT_19
   kind: mcp
   mcp_id: mcp1
   pin: 13
   output_type: light
-  
+
 - id: OUT_20
   kind: mcp
   mcp_id: mcp1
   pin: 12
   output_type: light
-  
+
 - id: OUT_21
   kind: mcp
   mcp_id: mcp1
   pin: 11
   output_type: light
-  
+
 - id: OUT_22
- kind: mcp
- mcp_id: mcp1
- pin: 10
- output_type: light
-  
+  kind: mcp
+  mcp_id: mcp1
+  pin: 13
+  output_type: light
+
 - id: OUT_23
   kind: mcp
   mcp_id: mcp1
   pin: 9
   output_type: light
-  
+
 - id: OUT_24
   kind: mcp
   mcp_id: mcp1
   pin: 8
   output_type: light
-  
-  
+
+
 # mcp2 - lower right 8 relays
 - id: OUT_25
   kind: mcp
   mcp_id: mcp2
   pin: 15
   output_type: light
-  
+
 - id: OUT_26
- kind: mcp
- mcp_id: mcp2
- pin: 14
- output_type: light
-  
+  kind: mcp
+  mcp_id: mcp2
+  pin: 9
+  output_type: light
+
 - id: OUT_27
   kind: mcp
   mcp_id: mcp2
   pin: 13
   output_type: light
-  
+
 - id: OUT_28
   kind: mcp
   mcp_id: mcp2
   pin: 12
   output_type: light
-  
+
 - id: OUT_29
   kind: mcp
   mcp_id: mcp2
   pin: 11
   output_type: light
-  
+
 - id: OUT_30
   kind: mcp
   mcp_id: mcp2
   pin: 10
   output_type: light
-  
+
 - id: OUT_31
   kind: mcp
   mcp_id: mcp2
   pin: 9
   output_type: light
-  
+
 - id: OUT_32
   kind: mcp
   mcp_id: mcp2
-  pin: 8
+  pin: 15
   output_type: light
diff --git a/boneio/helper/__init__.py b/boneio/helper/__init__.py
index b51898a..0596fa4 100644
--- a/boneio/helper/__init__.py
+++ b/boneio/helper/__init__.py
@@ -1,39 +1,38 @@
 """Helper dir for BoneIO."""
 
+from boneio.helper.exceptions import GPIOInputException, I2CError
 from boneio.helper.gpio import (
+    GpioBaseClass,
+    configure_pin,
     edge_detect,
+    read_input,
     setup_input,
     setup_output,
-    read_input,
     write_output,
-    GpioBaseClass,
-    configure_pin,
 )
-from boneio.helper.oled import make_font
-from boneio.helper.mqtt import BasicMqtt
-from boneio.helper.stats import HostData, host_stats
-from boneio.helper.yaml_util import (
-    CustomValidator,
-    load_yaml_file,
-    schema_file,
-    load_config_from_string,
-    load_config_from_file,
-)
-from boneio.helper.state_manager import StateManager
 from boneio.helper.ha_discovery import (
-    ha_light_availabilty_message,
-    ha_switch_availabilty_message,
-    ha_sensor_temp_availabilty_message,
-    ha_button_availabilty_message,
+    ha_adc_sensor_availabilty_message,
     ha_binary_sensor_availabilty_message,
+    ha_button_availabilty_message,
     ha_input_availabilty_message,
+    ha_light_availabilty_message,
     ha_sensor_availabilty_message,
-    ha_adc_sensor_availabilty_message,
+    ha_sensor_temp_availabilty_message,
+    ha_switch_availabilty_message,
 )
-from boneio.helper.exceptions import GPIOInputException, I2CError
+from boneio.helper.mqtt import BasicMqtt
+from boneio.helper.oled import make_font
 from boneio.helper.queue import UniqueQueue
+from boneio.helper.state_manager import StateManager
+from boneio.helper.stats import HostData, host_stats
 from boneio.helper.timeperiod import TimePeriod
-
+from boneio.helper.yaml_util import (
+    CustomValidator,
+    load_config_from_file,
+    load_config_from_string,
+    load_yaml_file,
+    schema_file,
+)
 
 __all__ = [
     "CustomValidator",
diff --git a/boneio/helper/config.py b/boneio/helper/config.py
index 897b430..e3aed59 100644
--- a/boneio/helper/config.py
+++ b/boneio/helper/config.py
@@ -1,9 +1,10 @@
 """
 Module to provide basic config options.
 """
-from boneio.const import BONEIO, HOMEASSISTANT
 from _collections_abc import dict_values
 
+from boneio.const import BONEIO, HOMEASSISTANT
+
 
 class ConfigHelper:
     def __init__(
diff --git a/boneio/helper/ds2482/onewire.py b/boneio/helper/ds2482/onewire.py
index c740f43..5647f51 100644
--- a/boneio/helper/ds2482/onewire.py
+++ b/boneio/helper/ds2482/onewire.py
@@ -2,10 +2,10 @@
 Module by https://github.com/fgervais/ds2482
 """
 import adafruit_onewire.bus
-import busio
+from onewireio import OneWire as OneWireIO
 
 
-class OneWire(busio.OneWire):
+class OneWire(OneWireIO):
     def __init__(self, ds2482):
         self.ds2482 = ds2482
 
diff --git a/boneio/helper/events.py b/boneio/helper/events.py
index d3972de..1de2c8e 100644
--- a/boneio/helper/events.py
+++ b/boneio/helper/events.py
@@ -1,10 +1,11 @@
 import asyncio
 import datetime as dt
-import signal
 import logging
+import signal
 import time
-from typing import Callable, Optional
 from datetime import datetime
+from typing import Callable, Optional
+
 from boneio.helper.util import callback
 
 _LOGGER = logging.getLogger(__name__)
diff --git a/boneio/helper/gpio.py b/boneio/helper/gpio.py
index 03e14ec..239ba41 100644
--- a/boneio/helper/gpio.py
+++ b/boneio/helper/gpio.py
@@ -15,19 +15,14 @@ def __init__(self):
 
     pass
 
-from boneio.helper.exceptions import GPIOInputException
-from boneio.const import LOW, FALLING, Gpio_Edges, Gpio_States
-from boneio.helper.timeperiod import TimePeriod
-
-from typing import Callable
 import subprocess
+from typing import Callable
 
-from boneio.const import (
-    CONFIG_PIN,
-    GPIO as GPIO_STR,
-    GPIO_MODE,
-    ClickTypes,
-)
+from boneio.const import CONFIG_PIN, FALLING
+from boneio.const import GPIO as GPIO_STR
+from boneio.const import GPIO_MODE, LOW, ClickTypes, Gpio_Edges, Gpio_States
+from boneio.helper.exceptions import GPIOInputException
+from boneio.helper.timeperiod import TimePeriod
 
 _LOGGER = logging.getLogger(__name__)
 
diff --git a/boneio/helper/ha_discovery.py b/boneio/helper/ha_discovery.py
index 1565356..2da4ea9 100644
--- a/boneio/helper/ha_discovery.py
+++ b/boneio/helper/ha_discovery.py
@@ -1,22 +1,20 @@
-from boneio.version import __version__
-
-
 from boneio.const import (
     CLOSE,
     CLOSED,
     CLOSING,
     COVER,
     INPUT,
+    INPUT_SENSOR,
     OFF,
     ON,
     OPEN,
     OPENING,
     RELAY,
-    STATE,
     SENSOR,
-    INPUT_SENSOR,
+    STATE,
     STOP,
 )
+from boneio.version import __version__
 
 
 def ha_availabilty_message(
diff --git a/boneio/helper/loader.py b/boneio/helper/loader.py
index d256929..d37ccbc 100644
--- a/boneio/helper/loader.py
+++ b/boneio/helper/loader.py
@@ -1,17 +1,20 @@
 from __future__ import annotations
 
-import logging
 import asyncio
+import logging
 import time
-from typing import TYPE_CHECKING, Any, Callable
 from collections import namedtuple
+from typing import TYPE_CHECKING, Any, Callable
 
 from adafruit_mcp230xx.mcp23017 import MCP23017
+from adafruit_onewire.bus import OneWireAddress
+
 from boneio.const import (
     ACTIONS,
     ADDRESS,
     BINARY_SENSOR,
     COVER,
+    DEVICE_CLASS,
     GPIO,
     ID,
     INIT_SLEEP,
@@ -31,7 +34,6 @@
     SENSOR,
     SHOW_HA,
     UPDATE_INTERVAL,
-    DEVICE_CLASS,
 )
 from boneio.cover import Cover
 from boneio.helper import (
@@ -43,22 +45,21 @@
     ha_input_availabilty_message,
     ha_sensor_temp_availabilty_message,
 )
-from adafruit_onewire.bus import OneWireAddress
-from boneio.helper.ds2482 import DS2482, OneWireBus, ds_address, DS2482_ADDRESS
+from boneio.helper.ds2482 import DS2482, DS2482_ADDRESS, OneWireBus, ds_address
 from boneio.helper.ha_discovery import ha_cover_availabilty_message
 from boneio.helper.timeperiod import TimePeriod
 from boneio.input.gpio import GpioInputButton
-from boneio.helper.config import ConfigHelper
 from boneio.sensor import DallasSensor
 
 # Typing imports that create a circular dependency
 if TYPE_CHECKING:
     from ..manager import Manager
-from boneio.modbus import Modbus
+
+from busio import I2C
+
 from boneio.relay import GpioRelay, MCPRelay
 from boneio.sensor import GpioADCSensor, initialize_adc
 from boneio.sensor.gpio import GpioInputSensor
-from busio import I2C
 
 _LOGGER = logging.getLogger(__name__)
 
diff --git a/boneio/helper/logger.py b/boneio/helper/logger.py
index 747c00f..bf20e76 100644
--- a/boneio/helper/logger.py
+++ b/boneio/helper/logger.py
@@ -1,4 +1,5 @@
 import logging
+
 from boneio.const import PAHO, PYMODBUS
 from boneio.version import __version__
 
diff --git a/boneio/helper/state_manager.py b/boneio/helper/state_manager.py
index 646e9c0..519ce82 100644
--- a/boneio/helper/state_manager.py
+++ b/boneio/helper/state_manager.py
@@ -1,6 +1,6 @@
 """State files manager."""
-import json
 import asyncio
+import json
 from typing import Any
 
 
diff --git a/boneio/helper/stats.py b/boneio/helper/stats.py
index 8d0c83a..82fe98e 100644
--- a/boneio/helper/stats.py
+++ b/boneio/helper/stats.py
@@ -12,20 +12,19 @@
     DISK,
     GIGABYTE,
     HOST,
+    IP,
+    MAC,
+    MASK,
     MEGABYTE,
     MEMORY,
     NETWORK,
+    NONE,
     SWAP,
     UPTIME,
-    IP,
-    MASK,
-    MAC,
-    NONE,
 )
 from boneio.sensor import LM75Sensor, MCP9808Sensor
 from boneio.version import __version__
 
-
 intervals = (("d", 86400), ("h", 3600), ("m", 60))
 
 
diff --git a/boneio/helper/timeperiod.py b/boneio/helper/timeperiod.py
index 04b1962..938c03e 100644
--- a/boneio/helper/timeperiod.py
+++ b/boneio/helper/timeperiod.py
@@ -1,7 +1,6 @@
+import math
 from collections import OrderedDict
-
 from datetime import timedelta
-import math
 
 
 def is_approximately_integer(value):
diff --git a/boneio/helper/util.py b/boneio/helper/util.py
index 063371d..704f7aa 100644
--- a/boneio/helper/util.py
+++ b/boneio/helper/util.py
@@ -1,4 +1,4 @@
-from typing import Callable, TypeVar, Any
+from typing import Any, Callable, TypeVar
 
 CALLABLE_T = TypeVar("CALLABLE_T", bound=Callable[..., Any])
 CALLBACK_TYPE = Callable[[], None]
diff --git a/boneio/helper/yaml_util.py b/boneio/helper/yaml_util.py
index ef157f5..aa0b03a 100644
--- a/boneio/helper/yaml_util.py
+++ b/boneio/helper/yaml_util.py
@@ -1,16 +1,17 @@
-import re
 import fnmatch
-from collections import OrderedDict
 import logging
-from typing import Any, Tuple
 import os
-from cerberus import Validator, TypeDefinition
+import re
+from collections import OrderedDict
+from typing import Any, Tuple
+
+from cerberus import TypeDefinition, Validator
+from yaml import MarkedYAMLError, SafeLoader, YAMLError, load
+
 from boneio.const import COVER, ID, OUTPUT
-from yaml import load, YAMLError, SafeLoader, MarkedYAMLError
 from boneio.helper.exceptions import ConfigurationException
 from boneio.helper.timeperiod import TimePeriod
 
-
 schema_file = os.path.join(os.path.dirname(__file__), "../schema/schema.yaml")
 _LOGGER = logging.getLogger(__name__)
 
@@ -226,6 +227,12 @@ def _normalize_coerce_to_bool(self, value):
     def _normalize_coerce_lower(self, value):
         return str(value).lower()
 
+    def _normalize_coerce_upper(self, value):
+        return str(value).upper()
+
+    def _normalize_coerce_actions_output(self, value):
+        return str(value).lower()
+
     def _normalize_coerce_str(self, value):
         return str(value)
 
diff --git a/boneio/input/gpio.py b/boneio/input/gpio.py
index 7814843..2f6de06 100644
--- a/boneio/input/gpio.py
+++ b/boneio/input/gpio.py
@@ -3,12 +3,8 @@
 from datetime import datetime, timedelta
 from functools import partial
 
-from boneio.const import (
-    DOUBLE,
-    LONG,
-    SINGLE,
-)
-from boneio.helper import edge_detect, GpioBaseClass
+from boneio.const import DOUBLE, LONG, SINGLE
+from boneio.helper import GpioBaseClass, edge_detect
 
 # TIMINGS FOR BUTTONS
 DEBOUNCE_DURATION = timedelta(microseconds=150000)
diff --git a/boneio/manager.py b/boneio/manager.py
index d82ab99..e7c079d 100644
--- a/boneio/manager.py
+++ b/boneio/manager.py
@@ -1,7 +1,8 @@
 import asyncio
 import logging
-from typing import Callable, List, Optional, Set, Union
 from collections import deque
+from typing import Callable, List, Optional, Set, Union
+
 from board import SCL, SDA
 from busio import I2C
 
@@ -18,8 +19,6 @@
     MODBUS,
     MQTT,
     NONE,
-    OFF,
-    ON,
     ONLINE,
     OPEN,
     OUTPUT,
@@ -32,18 +31,18 @@
     UARTS,
     ClickTypes,
     InputTypes,
+    relay_actions,
 )
 from boneio.helper import (
     GPIOInputException,
     HostData,
     I2CError,
     StateManager,
-    ha_switch_availabilty_message,
-    ha_light_availabilty_message,
     ha_button_availabilty_message,
+    ha_light_availabilty_message,
+    ha_switch_availabilty_message,
     host_stats,
 )
-
 from boneio.helper.config import ConfigHelper
 from boneio.helper.events import EventBus
 from boneio.helper.exceptions import ModbusUartException
@@ -51,18 +50,16 @@
     configure_cover,
     configure_input,
     configure_relay,
+    create_ds2482_dallas_sensor,
     create_mcp23017,
     create_temp_sensor,
-    create_ds2482_dallas_sensor,
 )
+from boneio.helper.logger import configure_logger
 from boneio.helper.yaml_util import load_config_from_file
 from boneio.modbus import Modbus
-from boneio.helper.logger import configure_logger
 
 _LOGGER = logging.getLogger(__name__)
 
-relay_actions = {ON: "turn_on", OFF: "turn_off", "TOGGLE": "toggle"}
-
 
 class Manager:
     """Manager to communicate MQTT with GPIO inputs and outputs."""
@@ -107,39 +104,12 @@ def __init__(
         self._ds_onewire_bus = {}
         self._temp_sensors = []
         self._modbus = None
-        if modbus and modbus.get(UART) in UARTS:
-            try:
-                self._modbus = Modbus(UARTS[modbus.get(UART)])
-            except ModbusUartException:
-                _LOGGER.error(
-                    "This UART %s can't be used for modbus communication.",
-                    modbus.get(UART),
-                )
-                self._modbus = None
 
-        for sensor_type in (LM75, MCP_TEMP_9808):
-            if sensors.get(sensor_type):
-                for temp_def in sensors.get(sensor_type):
-                    temp_sensor = create_temp_sensor(
-                        manager=self,
-                        topic_prefix=self._config_helper.topic_prefix,
-                        sensor_type=sensor_type,
-                        temp_def=temp_def,
-                        i2cbusio=self._i2cbusio,
-                    )
-                    if temp_sensor:
-                        self._temp_sensors.append(temp_sensor)
+        self._configure_modbus(modbus=modbus)
 
-        if sensors.get(MODBUS) and self._modbus:
-            from boneio.helper.loader import create_modbus_sensors
+        self._configure_temp_sensors(sensors=sensors)
 
-            create_modbus_sensors(
-                manager=self,
-                event_bus=self._event_bus,
-                sensors=sensors.get(MODBUS),
-                modbus=self._modbus,
-                config_helper=self._config_helper,
-            )
+        self._configure_modbus_sensors(sensors=sensors)
 
         self.grouped_outputs = create_mcp23017(
             manager=self, mcp23017=mcp23017, i2cbusio=self._i2cbusio
@@ -172,14 +142,7 @@ def __init__(
                     )
                 )
 
-        if adc_list:
-            from boneio.helper.loader import create_adc
-
-            create_adc(
-                manager=self,
-                topic_prefix=self._config_helper.topic_prefix,
-                adc_list=adc_list,
-            )
+        self._configure_adc(adc_list=adc_list)
 
         for _config in relay_pins:
             _id = _config[ID].replace(" ", "")
@@ -285,6 +248,53 @@ def __init__(
 
         _LOGGER.info("BoneIO manager is ready.")
 
+    def _configure_adc(self, adc_list: Optional[List]) -> None:
+        if adc_list:
+            from boneio.helper.loader import create_adc
+
+            create_adc(
+                manager=self,
+                topic_prefix=self._config_helper.topic_prefix,
+                adc_list=adc_list,
+            )
+
+    def _configure_modbus(self, modbus: dict) -> None:
+        if modbus and modbus.get(UART) in UARTS:
+            try:
+                self._modbus = Modbus(UARTS[modbus.get(UART)])
+            except ModbusUartException:
+                _LOGGER.error(
+                    "This UART %s can't be used for modbus communication.",
+                    modbus.get(UART),
+                )
+                self._modbus = None
+
+    def _configure_temp_sensors(self, sensors: dict) -> None:
+        for sensor_type in (LM75, MCP_TEMP_9808):
+            if sensors.get(sensor_type):
+                for temp_def in sensors.get(sensor_type):
+                    temp_sensor = create_temp_sensor(
+                        manager=self,
+                        topic_prefix=self._config_helper.topic_prefix,
+                        sensor_type=sensor_type,
+                        temp_def=temp_def,
+                        i2cbusio=self._i2cbusio,
+                    )
+                    if temp_sensor:
+                        self._temp_sensors.append(temp_sensor)
+
+    def _configure_modbus_sensors(self, sensors: dict) -> None:
+        if sensors.get(MODBUS) and self._modbus:
+            from boneio.helper.loader import create_modbus_sensors
+
+            create_modbus_sensors(
+                manager=self,
+                event_bus=self._event_bus,
+                sensors=sensors.get(MODBUS),
+                modbus=self._modbus,
+                config_helper=self._config_helper,
+            )
+
     async def reconnect_callback(self) -> None:
         """Function to invoke when connection to MQTT is (re-)established."""
         _LOGGER.info("Sending online state.")
diff --git a/boneio/modbus.py b/boneio/modbus.py
index 5829bef..82212f0 100644
--- a/boneio/modbus.py
+++ b/boneio/modbus.py
@@ -2,19 +2,18 @@
 
 import asyncio
 import logging
-from boneio.helper import configure_pin
-from boneio.helper.exceptions import ModbusUartException
-from boneio.const import ID, RX, TX, UART, REGISTERS
-from pymodbus.client.sync import (
-    BaseModbusClient,
-    ModbusSerialClient,
-)
-from pymodbus.register_read_message import ReadInputRegistersResponse
-from pymodbus.payload import BinaryPayloadDecoder
-from pymodbus.constants import Endian
 from typing import Any
+
+from pymodbus.client.sync import BaseModbusClient, ModbusSerialClient
+from pymodbus.constants import Endian
 from pymodbus.exceptions import ModbusException
+from pymodbus.payload import BinaryPayloadDecoder
 from pymodbus.pdu import ModbusResponse
+from pymodbus.register_read_message import ReadInputRegistersResponse
+
+from boneio.const import ID, REGISTERS, RX, TX, UART
+from boneio.helper import configure_pin
+from boneio.helper.exceptions import ModbusUartException
 
 _LOGGER = logging.getLogger(__name__)
 
diff --git a/boneio/mqtt_client.py b/boneio/mqtt_client.py
index c946a13..ad64e67 100644
--- a/boneio/mqtt_client.py
+++ b/boneio/mqtt_client.py
@@ -10,12 +10,12 @@
 from typing import Any, Callable, Optional, Set, Tuple, Union
 
 import paho.mqtt.client as mqtt
-from asyncio_mqtt import Client as AsyncioClient, Will
-from asyncio_mqtt import MqttError
+from asyncio_mqtt import Client as AsyncioClient
+from asyncio_mqtt import MqttError, Will
 from paho.mqtt.properties import Properties
 from paho.mqtt.subscribeoptions import SubscribeOptions
 
-from boneio.const import PAHO, STATE, ONLINE
+from boneio.const import ONLINE, PAHO, STATE
 from boneio.helper import UniqueQueue
 from boneio.helper.config import ConfigHelper
 
diff --git a/boneio/oled.py b/boneio/oled.py
index e47cf98..4fad16e 100644
--- a/boneio/oled.py
+++ b/boneio/oled.py
@@ -3,20 +3,20 @@
 from itertools import cycle
 from typing import List
 
+from luma.core.error import DeviceNotFoundError
 from luma.core.interface.serial import i2c
 from luma.core.render import canvas
 from luma.oled.device import sh1106
-from luma.core.error import DeviceNotFoundError
 from PIL import ImageDraw
 
 from boneio.const import CPU, DISK, MEMORY, NETWORK, OLED_PIN, SWAP, UPTIME, WHITE
 from boneio.helper import (
     HostData,
+    I2CError,
+    TimePeriod,
     edge_detect,
     make_font,
     setup_input,
-    I2CError,
-    TimePeriod,
 )
 from boneio.helper.events import async_track_point_in_time, utcnow
 
diff --git a/boneio/relay/basic.py b/boneio/relay/basic.py
index 4dde74b..7f334cc 100644
--- a/boneio/relay/basic.py
+++ b/boneio/relay/basic.py
@@ -4,7 +4,7 @@
 import logging
 from typing import Callable
 
-from boneio.const import LIGHT, OFF, ON, RELAY, STATE, SWITCH, NONE
+from boneio.const import LIGHT, NONE, OFF, ON, RELAY, STATE, SWITCH
 from boneio.helper import BasicMqtt
 
 _LOGGER = logging.getLogger(__name__)
diff --git a/boneio/relay/gpio.py b/boneio/relay/gpio.py
index cd60c31..d9c13a2 100644
--- a/boneio/relay/gpio.py
+++ b/boneio/relay/gpio.py
@@ -5,9 +5,9 @@
 
 import logging
 
+from boneio.const import HIGH, LOW
 from boneio.helper import read_input, setup_output, write_output
 from boneio.relay.basic import BasicRelay
-from boneio.const import HIGH, LOW
 
 _LOGGER = logging.getLogger(__name__)
 
diff --git a/boneio/relay/mcp.py b/boneio/relay/mcp.py
index 83843e0..477b887 100644
--- a/boneio/relay/mcp.py
+++ b/boneio/relay/mcp.py
@@ -1,11 +1,13 @@
 """MCP23017 Relay module."""
 
 import logging
+
 from adafruit_mcp230xx.mcp23017 import MCP23017, DigitalInOut
+
+from boneio.const import NONE, SWITCH
+from boneio.helper.events import async_track_point_in_time, utcnow
 from boneio.helper.util import callback
 from boneio.relay.basic import BasicRelay
-from boneio.const import SWITCH, NONE
-from boneio.helper.events import async_track_point_in_time, utcnow
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -24,11 +26,10 @@ def __init__(
     ) -> None:
         """Initialize MCP relay."""
         self._pin: DigitalInOut = mcp.get_pin(pin)
-        self._pin.switch_to_output(value=True)
         if output_type == NONE:
             """Just in case to not restore state of covers etc."""
             restored_state = False
-        self._pin.value = restored_state
+        self._pin.switch_to_output(value=restored_state)
         super().__init__(
             **kwargs, output_type=output_type, restored_state=restored_state
         )
diff --git a/boneio/runner.py b/boneio/runner.py
index 82e2e3d..dd3071b 100644
--- a/boneio/runner.py
+++ b/boneio/runner.py
@@ -2,10 +2,12 @@
 import asyncio
 import logging
 import os
+
 from boneio.const import (
     ADC,
     COVER,
     DALLAS,
+    DS2482,
     ENABLED,
     HA_DISCOVERY,
     HOST,
@@ -21,14 +23,13 @@
     PORT,
     TOPIC_PREFIX,
     USERNAME,
-    DS2482,
 )
-
-_LOGGER = logging.getLogger(__name__)
 from boneio.helper import StateManager
+from boneio.helper.config import ConfigHelper
 from boneio.manager import Manager
 from boneio.mqtt_client import MQTTClient
-from boneio.helper.config import ConfigHelper
+
+_LOGGER = logging.getLogger(__name__)
 
 
 async def async_run(
diff --git a/boneio/schema/actions.yaml b/boneio/schema/actions.yaml
index f0d2969..dab8119 100644
--- a/boneio/schema/actions.yaml
+++ b/boneio/schema/actions.yaml
@@ -29,6 +29,9 @@ schema:
     default: toggle
     dependencies:
       action: ['output']
+    coerce:
+      - lower
+      - actions_output
     meta:
       label: If output action chosen then what action to perform.
   action_mqtt_msg:
diff --git a/boneio/schema/schema.yaml b/boneio/schema/schema.yaml
index 93c1faf..6bddf75 100644
--- a/boneio/schema/schema.yaml
+++ b/boneio/schema/schema.yaml
@@ -62,7 +62,7 @@ logger:
       type: dict
       meta:
         label: List of dict module\:level.
-      
+
 
 
 oled:
diff --git a/boneio/sensor/__init__.py b/boneio/sensor/__init__.py
index 0eb554d..852d2b1 100644
--- a/boneio/sensor/__init__.py
+++ b/boneio/sensor/__init__.py
@@ -1,9 +1,9 @@
 """Sensor module."""
+from boneio.sensor.adc import GpioADCSensor, initialize_adc
+from boneio.sensor.gpio import GpioInputSensor
+from boneio.sensor.temp.dallas import DallasSensor
 from boneio.sensor.temp.lm75 import LM75Sensor
 from boneio.sensor.temp.mcp9808 import MCP9808Sensor
-from boneio.sensor.temp.dallas import DallasSensor
-from boneio.sensor.gpio import GpioInputSensor
-from boneio.sensor.adc import initialize_adc, GpioADCSensor
 
 __all__ = [
     "DallasSensor",
diff --git a/boneio/sensor/adc.py b/boneio/sensor/adc.py
index 0c5eae0..f2ad32c 100644
--- a/boneio/sensor/adc.py
+++ b/boneio/sensor/adc.py
@@ -1,6 +1,6 @@
 """ADC GPIO BBB sensor."""
-import logging
 import asyncio
+import logging
 
 from boneio.const import SENSOR
 from boneio.helper import BasicMqtt
diff --git a/boneio/sensor/gpio.py b/boneio/sensor/gpio.py
index 2bc9bc4..849fd5d 100644
--- a/boneio/sensor/gpio.py
+++ b/boneio/sensor/gpio.py
@@ -3,7 +3,7 @@
 from functools import partial
 
 from boneio.const import BOTH, PRESSED, RELEASED
-from boneio.helper import edge_detect, GpioBaseClass
+from boneio.helper import GpioBaseClass, edge_detect
 
 _LOGGER = logging.getLogger(__name__)
 
diff --git a/boneio/sensor/modbus/__init__.py b/boneio/sensor/modbus/__init__.py
index 00bc7cd..ae2e103 100644
--- a/boneio/sensor/modbus/__init__.py
+++ b/boneio/sensor/modbus/__init__.py
@@ -1,28 +1,27 @@
-import logging
 import asyncio
-from datetime import datetime
-
-from struct import unpack
 import json
+import logging
 import os
+from datetime import datetime
+from struct import unpack
 
 from boneio.const import (
     ADDRESS,
-    MODEL,
-    SENSOR,
-    STATE,
-    ONLINE,
-    OFFLINE,
     BASE,
     LENGTH,
+    MODEL,
+    OFFLINE,
+    ONLINE,
     REGISTERS,
+    SENSOR,
+    STATE,
 )
 from boneio.helper import BasicMqtt
+from boneio.helper.config import ConfigHelper
+from boneio.helper.events import EventBus
 from boneio.helper.ha_discovery import modbus_sensor_availabilty_message
 from boneio.helper.timeperiod import TimePeriod
-from boneio.helper.config import ConfigHelper
 from boneio.modbus import Modbus
-from boneio.helper.events import EventBus
 
 _LOGGER = logging.getLogger(__name__)
 
diff --git a/boneio/sensor/temp/__init__.py b/boneio/sensor/temp/__init__.py
index 1536754..06c7fd3 100644
--- a/boneio/sensor/temp/__init__.py
+++ b/boneio/sensor/temp/__init__.py
@@ -4,17 +4,12 @@
 from datetime import datetime, timedelta
 from typing import Optional
 
-from boneio.const import STATE, SENSOR, TEMPERATURE
-
-
-from boneio.helper.exceptions import I2CError
+from boneio.const import SENSOR, STATE, TEMPERATURE
 from boneio.helper import BasicMqtt
-
-from boneio.helper.util import callback
 from boneio.helper.events import async_track_point_in_time, utcnow
-
-
+from boneio.helper.exceptions import I2CError
 from boneio.helper.timeperiod import TimePeriod
+from boneio.helper.util import callback
 
 
 class TempSensor(BasicMqtt):
@@ -28,7 +23,7 @@ def __init__(
         i2c,
         address: str,
         id: str = DefaultName,
-        update_interval: int = TimePeriod(seconds=60),
+        update_interval: TimePeriod = TimePeriod(seconds=60),
         **kwargs
     ):
         """Initialize Temp class."""
diff --git a/boneio/sensor/temp/dallas.py b/boneio/sensor/temp/dallas.py
index 1249e9f..5fbfa53 100644
--- a/boneio/sensor/temp/dallas.py
+++ b/boneio/sensor/temp/dallas.py
@@ -6,16 +6,13 @@
 # from datetime import timedelta
 from adafruit_ds18x20 import DS18X20
 from adafruit_onewire.bus import OneWireAddress
-from boneio.const import SENSOR, TEMPERATURE
-
 
-from boneio.helper.exceptions import OneWireError
+from boneio.const import SENSOR, TEMPERATURE
 from boneio.helper import BasicMqtt
-
 from boneio.helper.events import utcnow
-
-
+from boneio.helper.exceptions import OneWireError
 from boneio.helper.timeperiod import TimePeriod
+
 from . import TempSensor
 
 
@@ -26,13 +23,13 @@ class DallasSensor(TempSensor):
     def __init__(
         self,
         bus,
+        update_interval: TimePeriod,
         address: OneWireAddress,
         id: str = DefaultName,
-        update_interval: int = TimePeriod(seconds=60),
         **kwargs
     ):
         """Initialize Temp class."""
-        self._update_interval = update_interval
+        self._update_interval = update_interval or TimePeriod(seconds=60)
         self._loop = asyncio.get_event_loop()
         BasicMqtt.__init__(self, id=id, topic_type=SENSOR, **kwargs)
         try:
diff --git a/boneio/sensor/temp/lm75.py b/boneio/sensor/temp/lm75.py
index de88a3f..0b367d8 100644
--- a/boneio/sensor/temp/lm75.py
+++ b/boneio/sensor/temp/lm75.py
@@ -1,8 +1,10 @@
 """LM75 temp sensor."""
-from . import TempSensor
 from adafruit_pct2075 import PCT2075
+
 from boneio.const import LM75
 
+from . import TempSensor
+
 
 class LM75Sensor(TempSensor):
     """Represent LM75 sensor in BoneIO."""
diff --git a/boneio/sensor/temp/mcp9808.py b/boneio/sensor/temp/mcp9808.py
index 24b5a21..b8f8b1e 100644
--- a/boneio/sensor/temp/mcp9808.py
+++ b/boneio/sensor/temp/mcp9808.py
@@ -1,9 +1,11 @@
 """MCP9808 temp sensor."""
 
-from . import TempSensor
 from adafruit_mcp9808 import MCP9808
+
 from boneio.const import MCP_TEMP_9808
 
+from . import TempSensor
+
 
 class MCP9808Sensor(TempSensor):
     """Represent MCP9808 sensor in BoneIO."""
diff --git a/boneio/version.py b/boneio/version.py
index 8e2b540..b2c09a3 100644
--- a/boneio/version.py
+++ b/boneio/version.py
@@ -1,2 +1,2 @@
 # flake8: noqa
-__version__ = "0.3.0"
+__version__ = "0.4.0"
diff --git a/create_dist.sh b/create_dist.sh
index b9d4107..42099cc 100755
--- a/create_dist.sh
+++ b/create_dist.sh
@@ -4,4 +4,3 @@
 rm -rf dist/*
 python3 setup.py sdist bdist_wheel
 python3 -m twine upload dist/*
-
diff --git a/install_script.py b/install_script.py
index 610de8f..db459a5 100755
--- a/install_script.py
+++ b/install_script.py
@@ -1,15 +1,15 @@
 #!/usr/bin/env python3
-import subprocess
+import itertools
+import logging
+import os
+import re
 import shlex
+import subprocess
 import sys
-import itertools
 from collections import namedtuple
 from shutil import copyfile
-import os
-import logging
-import yaml
-import re
 
+import yaml
 
 _LOGGER = logging.getLogger(__name__)
 logging.basicConfig(level=logging.INFO)
diff --git a/mypy.ini b/mypy.ini
deleted file mode 100644
index 6addb7e..0000000
--- a/mypy.ini
+++ /dev/null
@@ -1,24 +0,0 @@
-# Automatically generated by hassfest.
-#
-# To update, run python3 -m script.hassfest -p mypy_config
-
-[mypy]
-python_version = 3.7
-show_error_codes = true
-follow_imports = silent
-ignore_missing_imports = true
-strict_equality = true
-warn_incomplete_stub = true
-warn_redundant_casts = true
-warn_unused_configs = true
-warn_unused_ignores = true
-enable_error_code = ignore-without-code
-check_untyped_defs = true
-disallow_incomplete_defs = true
-disallow_subclassing_any = true
-disallow_untyped_calls = true
-disallow_untyped_decorators = true
-disallow_untyped_defs = true
-no_implicit_optional = true
-warn_return_any = true
-warn_unreachable = true
diff --git a/pdm.lock b/pdm.lock
new file mode 100644
index 0000000..43bdede
--- /dev/null
+++ b/pdm.lock
@@ -0,0 +1,963 @@
+[[package]]
+name = "adafruit-bbio"
+version = "1.2.0"
+summary = "A module to control BeagleBone IO channels"
+
+[[package]]
+name = "adafruit-blinka"
+version = "8.0.2"
+requires_python = ">=3.7.0"
+summary = "CircuitPython APIs for non-CircuitPython versions of Python such as CPython on Linux and MicroPython."
+dependencies = [
+    "Adafruit-PlatformDetect>=3.13.0",
+    "Adafruit-PureIO>=1.1.7",
+    "adafruit-circuitpython-typing",
+    "pyftdi>=0.40.0",
+]
+
+[[package]]
+name = "adafruit-circuitpython-busdevice"
+version = "5.1.10"
+requires_python = ">=3.7.0"
+summary = "CircuitPython bus device classes to manage bus sharing."
+dependencies = [
+    "Adafruit-Blinka>=7.0.0",
+    "adafruit-circuitpython-typing",
+]
+
+[[package]]
+name = "adafruit-circuitpython-ds18x20"
+version = "1.3.12"
+summary = "CircuitPython driver for Dallas 1-Wire temperature sensor."
+dependencies = [
+    "Adafruit-Blinka",
+    "adafruit-circuitpython-onewire",
+]
+
+[[package]]
+name = "adafruit-circuitpython-mcp230xx"
+version = "2.5.5"
+summary = "CircuitPython library for controlling a MCP23008 or MCP23017 I2C GPIO expander."
+dependencies = [
+    "Adafruit-Blinka",
+    "adafruit-circuitpython-busdevice",
+]
+
+[[package]]
+name = "adafruit-circuitpython-mcp9808"
+version = "3.3.14"
+summary = "CircuitPython library for MCP9808 high accuracy temperature sensor."
+dependencies = [
+    "Adafruit-Blinka",
+    "adafruit-circuitpython-busdevice",
+    "adafruit-circuitpython-register",
+]
+
+[[package]]
+name = "adafruit-circuitpython-onewire"
+version = "2.0.0"
+summary = "CircuitPython OneWire helper library for 1-wire bus devices."
+dependencies = [
+    "Adafruit-Blinka",
+    "adafruit-circuitpython-busdevice",
+]
+
+[[package]]
+name = "adafruit-circuitpython-pct2075"
+version = "1.1.14"
+summary = "CircuitPython library for the NXP PCT2075 Digital Temperature Sensor"
+dependencies = [
+    "Adafruit-Blinka",
+    "adafruit-circuitpython-busdevice",
+    "adafruit-circuitpython-register",
+]
+
+[[package]]
+name = "adafruit-circuitpython-register"
+version = "1.9.10"
+summary = "CircuitPython data descriptor classes to represent hardware registers on I2C and SPI devices."
+
+[[package]]
+name = "adafruit-circuitpython-typing"
+version = "1.7.1"
+summary = "Types needed for type annotation that are not in `typing`"
+dependencies = [
+    "adafruit-circuitpython-busdevice",
+    "typing-extensions; python_version <= \"3.7\"",
+]
+
+[[package]]
+name = "adafruit-platformdetect"
+version = "3.24.1"
+requires_python = ">=3.7.0"
+summary = "Platform detection for use by libraries like Adafruit-Blinka."
+
+[[package]]
+name = "adafruit-pureio"
+version = "1.1.9"
+requires_python = ">=3.5.0"
+summary = "Pure python (i.e. no native extensions) access to Linux IO    including I2C and SPI. Drop in replacement for smbus and spidev modules."
+
+[[package]]
+name = "asyncio-mqtt"
+version = "0.12.1"
+summary = "Idomatic asyncio wrapper around paho-mqtt."
+dependencies = [
+    "paho-mqtt>=1.6.0",
+]
+
+[[package]]
+name = "bandit"
+version = "1.7.4"
+requires_python = ">=3.7"
+summary = "Security oriented static analyser for python code."
+dependencies = [
+    "GitPython>=1.0.1",
+    "PyYAML>=5.3.1",
+    "colorama>=0.3.9; platform_system == \"Windows\"",
+    "stevedore>=1.20.0",
+]
+
+[[package]]
+name = "black"
+version = "22.3.0"
+requires_python = ">=3.6.2"
+summary = "The uncompromising code formatter."
+dependencies = [
+    "click>=8.0.0",
+    "mypy-extensions>=0.4.3",
+    "pathspec>=0.9.0",
+    "platformdirs>=2",
+    "tomli>=1.1.0; python_version < \"3.11\"",
+    "typed-ast>=1.4.2; python_version < \"3.8\" and implementation_name == \"cpython\"",
+    "typing-extensions>=3.10.0.0; python_version < \"3.10\"",
+]
+
+[[package]]
+name = "cbor2"
+version = "5.4.2"
+requires_python = ">=3.6"
+summary = "Pure Python CBOR (de)serializer with extensive tag support"
+
+[[package]]
+name = "cerberus"
+version = "1.3.4"
+requires_python = ">=2.7"
+summary = "Lightweight, extensible schema and data validation tool for Python dictionaries."
+dependencies = [
+    "setuptools",
+]
+
+[[package]]
+name = "cfgv"
+version = "3.3.1"
+requires_python = ">=3.6.1"
+summary = "Validate configuration and produce human readable error messages."
+
+[[package]]
+name = "click"
+version = "8.1.3"
+requires_python = ">=3.7"
+summary = "Composable command line interface toolkit"
+dependencies = [
+    "colorama; platform_system == \"Windows\"",
+    "importlib-metadata; python_version < \"3.8\"",
+]
+
+[[package]]
+name = "colorama"
+version = "0.4.5"
+requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+summary = "Cross-platform colored terminal text."
+
+[[package]]
+name = "colorlog"
+version = "6.6.0"
+requires_python = ">=3.6"
+summary = "Add colours to the output of Python's logging module."
+dependencies = [
+    "colorama; sys_platform == \"win32\"",
+]
+
+[[package]]
+name = "deprecated"
+version = "1.2.13"
+requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+summary = "Python @deprecated decorator to deprecate old python classes, functions or methods."
+dependencies = [
+    "wrapt<2,>=1.10",
+]
+
+[[package]]
+name = "distlib"
+version = "0.3.4"
+summary = "Distribution utilities"
+
+[[package]]
+name = "filelock"
+version = "3.7.1"
+requires_python = ">=3.7"
+summary = "A platform independent file lock."
+
+[[package]]
+name = "flake8"
+version = "4.0.1"
+requires_python = ">=3.6"
+summary = "the modular source code checker: pep8 pyflakes and co"
+dependencies = [
+    "importlib-metadata<4.3; python_version < \"3.8\"",
+    "mccabe<0.7.0,>=0.6.0",
+    "pycodestyle<2.9.0,>=2.8.0",
+    "pyflakes<2.5.0,>=2.4.0",
+]
+
+[[package]]
+name = "gitdb"
+version = "4.0.9"
+requires_python = ">=3.6"
+summary = "Git Object Database"
+dependencies = [
+    "smmap<6,>=3.0.1",
+]
+
+[[package]]
+name = "gitpython"
+version = "3.1.27"
+requires_python = ">=3.7"
+summary = "GitPython is a python library used to interact with Git repositories"
+dependencies = [
+    "gitdb<5,>=4.0.1",
+    "typing-extensions>=3.7.4.3; python_version < \"3.8\"",
+]
+
+[[package]]
+name = "gpio"
+version = "0.3.0"
+summary = "gpio access via the standard linux sysfs interface"
+
+[[package]]
+name = "identify"
+version = "2.5.1"
+requires_python = ">=3.7"
+summary = "File identification library for Python"
+
+[[package]]
+name = "importlib-metadata"
+version = "4.2.0"
+requires_python = ">=3.6"
+summary = "Read metadata from Python packages"
+dependencies = [
+    "typing-extensions>=3.6.4; python_version < \"3.8\"",
+    "zipp>=0.5",
+]
+
+[[package]]
+name = "isort"
+version = "5.10.1"
+requires_python = ">=3.6.1,<4.0"
+summary = "A Python utility / library to sort Python imports."
+
+[[package]]
+name = "luma.core"
+version = "2.3.1"
+requires_python = "<4,>=3.6"
+summary = "A component library to support SBC display drivers"
+dependencies = [
+    "RPI.GPIO; platform_system == \"Linux\"",
+    "cbor2",
+    "deprecated",
+    "pillow>=4.0.0",
+    "pyftdi",
+    "smbus2",
+    "spidev; platform_system == \"Linux\"",
+]
+
+[[package]]
+name = "luma.oled"
+version = "3.8.1"
+requires_python = ">=3.6, <4"
+summary = "A small library to drive an OLED device with either SSD1306, SSD1309, SSD1322, SSD1325, SSD1327, SSD1331, SSD1351, SSD1362, SH1106 or WS0010 chipset"
+dependencies = [
+    "luma.core>=2.0.0",
+]
+
+[[package]]
+name = "mccabe"
+version = "0.6.1"
+summary = "McCabe checker, plugin for flake8"
+
+[[package]]
+name = "mypy-extensions"
+version = "0.4.3"
+summary = "Experimental type system extensions for programs checked with the mypy typechecker."
+
+[[package]]
+name = "nodeenv"
+version = "1.6.0"
+summary = "Node.js virtual environment builder"
+
+[[package]]
+name = "paho-mqtt"
+version = "1.6.1"
+summary = "MQTT version 5.0/3.1.1 client class"
+
+[[package]]
+name = "pathspec"
+version = "0.9.0"
+requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+summary = "Utility library for gitignore style pattern matching of file paths."
+
+[[package]]
+name = "pbr"
+version = "5.9.0"
+requires_python = ">=2.6"
+summary = "Python Build Reasonableness"
+
+[[package]]
+name = "pillow"
+version = "9.1.1"
+requires_python = ">=3.7"
+summary = "Python Imaging Library (Fork)"
+
+[[package]]
+name = "platformdirs"
+version = "2.5.2"
+requires_python = ">=3.7"
+summary = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+
+[[package]]
+name = "pre-commit"
+version = "2.19.0"
+requires_python = ">=3.7"
+summary = "A framework for managing and maintaining multi-language pre-commit hooks."
+dependencies = [
+    "cfgv>=2.0.0",
+    "identify>=1.0.0",
+    "importlib-metadata; python_version < \"3.8\"",
+    "nodeenv>=0.11.1",
+    "pyyaml>=5.1",
+    "toml",
+    "virtualenv>=20.0.8",
+]
+
+[[package]]
+name = "psutil"
+version = "5.9.1"
+requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+summary = "Cross-platform lib for process and system monitoring in Python."
+
+[[package]]
+name = "pycodestyle"
+version = "2.8.0"
+requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+summary = "Python style guide checker"
+
+[[package]]
+name = "pyflakes"
+version = "2.4.0"
+requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+summary = "passive checker of Python programs"
+
+[[package]]
+name = "pyftdi"
+version = "0.54.0"
+requires_python = ">=3.7"
+summary = "FTDI device driver (pure Python)"
+dependencies = [
+    "pyserial>=3.0",
+    "pyusb!=1.2.0,>=1.0.0",
+]
+
+[[package]]
+name = "pymodbus"
+version = "2.5.3"
+requires_python = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"
+summary = "A fully featured modbus protocol stack in python"
+dependencies = [
+    "pyserial>=3.4",
+    "six>=1.15.0",
+]
+
+[[package]]
+name = "pyserial"
+version = "3.5"
+summary = "Python Serial Port Extension"
+
+[[package]]
+name = "pyserial-asyncio"
+version = "0.6"
+summary = "Python Serial Port Extension - Asynchronous I/O support"
+dependencies = [
+    "pyserial",
+]
+
+[[package]]
+name = "pyusb"
+version = "1.2.1"
+requires_python = ">=3.6.0"
+summary = "Python USB access module"
+
+[[package]]
+name = "pyyaml"
+version = "6.0"
+requires_python = ">=3.6"
+summary = "YAML parser and emitter for Python"
+
+[[package]]
+name = "rpi.gpio"
+version = "0.7.1"
+summary = "A module to control Raspberry Pi GPIO channels"
+
+[[package]]
+name = "setuptools"
+version = "62.6.0"
+requires_python = ">=3.7"
+summary = "Easily download, build, install, upgrade, and uninstall Python packages"
+
+[[package]]
+name = "six"
+version = "1.16.0"
+requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+summary = "Python 2 and 3 compatibility utilities"
+
+[[package]]
+name = "smbus2"
+version = "0.4.2"
+summary = "smbus2 is a drop-in replacement for smbus-cffi/smbus-python in pure Python"
+
+[[package]]
+name = "smmap"
+version = "5.0.0"
+requires_python = ">=3.6"
+summary = "A pure Python implementation of a sliding window memory map manager"
+
+[[package]]
+name = "spidev"
+version = "3.5"
+summary = "Python bindings for Linux SPI access through spidev"
+
+[[package]]
+name = "stevedore"
+version = "3.5.0"
+requires_python = ">=3.6"
+summary = "Manage dynamic plugins for Python applications"
+dependencies = [
+    "importlib-metadata>=1.7.0; python_version < \"3.8\"",
+    "pbr!=2.1.0,>=2.0.0",
+]
+
+[[package]]
+name = "toml"
+version = "0.10.2"
+requires_python = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+summary = "Python Library for Tom's Obvious, Minimal Language"
+
+[[package]]
+name = "tomli"
+version = "2.0.1"
+requires_python = ">=3.7"
+summary = "A lil' TOML parser"
+
+[[package]]
+name = "typed-ast"
+version = "1.5.4"
+requires_python = ">=3.6"
+summary = "a fork of Python 2 and 3 ast modules with type comment support"
+
+[[package]]
+name = "typing-extensions"
+version = "4.2.0"
+requires_python = ">=3.7"
+summary = "Backported and Experimental Type Hints for Python 3.7+"
+
+[[package]]
+name = "virtualenv"
+version = "20.14.1"
+requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+summary = "Virtual Python Environment builder"
+dependencies = [
+    "distlib<1,>=0.3.1",
+    "filelock<4,>=3.2",
+    "importlib-metadata>=0.12; python_version < \"3.8\"",
+    "platformdirs<3,>=2",
+    "six<2,>=1.9.0",
+]
+
+[[package]]
+name = "wrapt"
+version = "1.14.1"
+requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+summary = "Module for decorators, wrappers and monkey patching."
+
+[[package]]
+name = "zipp"
+version = "3.8.0"
+requires_python = ">=3.7"
+summary = "Backport of pathlib-compatible object wrapper for zip files"
+
+[metadata]
+lock_version = "3.1"
+content_hash = "sha256:9be8d2c67b7a406dcdb41ef51a7ccd064329904d6763a6c3b5e393bf7db01ba8"
+
+[metadata.files]
+"adafruit-bbio 1.2.0" = [
+    {file = "Adafruit_BBIO-1.2.0.tar.gz", hash = "sha256:5edcb8abd32b5f78365f6131f1d24cd78c419d60f469fc828518688cf39fdbad"},
+]
+"adafruit-blinka 8.0.2" = [
+    {file = "Adafruit-Blinka-8.0.2.tar.gz", hash = "sha256:a807b3ffd1ee2e13b8513e85af84e5d973a13088ca731abe8eb27742a6903b42"},
+]
+"adafruit-circuitpython-busdevice 5.1.10" = [
+    {file = "adafruit-circuitpython-busdevice-5.1.10.tar.gz", hash = "sha256:228df23033f3259b42b998701699293a3cdfd5599fa1cfb13557ad415bab8ab5"},
+]
+"adafruit-circuitpython-ds18x20 1.3.12" = [
+    {file = "adafruit-circuitpython-ds18x20-1.3.12.tar.gz", hash = "sha256:24951949b030bcf5aa03255ce64b6b4173811096bcb1bb9e1b6ef3d9e0217e7d"},
+]
+"adafruit-circuitpython-mcp230xx 2.5.5" = [
+    {file = "adafruit-circuitpython-mcp230xx-2.5.5.tar.gz", hash = "sha256:e5902db2b2371a633a1db710b657b85c7623287b3dd65088646b5c33f66752fc"},
+]
+"adafruit-circuitpython-mcp9808 3.3.14" = [
+    {file = "adafruit-circuitpython-mcp9808-3.3.14.tar.gz", hash = "sha256:1c5b1287bd10a150135e5a10d2764c0c71555893d05d0261468572a91a6a24dc"},
+]
+"adafruit-circuitpython-onewire 2.0.0" = [
+    {file = "adafruit-circuitpython-onewire-2.0.0.tar.gz", hash = "sha256:ef45fe42e8b0fd06347b712d128bfb7c0dae77465c40a8b7db55f15295138f6a"},
+]
+"adafruit-circuitpython-pct2075 1.1.14" = [
+    {file = "adafruit-circuitpython-pct2075-1.1.14.tar.gz", hash = "sha256:10feedcc53ae681d7b85ea930e1edc51fd1dc33d9278e84db34647b091185e68"},
+]
+"adafruit-circuitpython-register 1.9.10" = [
+    {file = "adafruit-circuitpython-register-1.9.10.tar.gz", hash = "sha256:62d67a24de825a7b14f7a6713ed77ce9e2d2bb3a6a4123aba13ba8f98d594f14"},
+]
+"adafruit-circuitpython-typing 1.7.1" = [
+    {file = "adafruit-circuitpython-typing-1.7.1.tar.gz", hash = "sha256:30051d7f2a5eeaed67d72cbae5a627fab7be97f2dede2f47d1385d7d8dee2474"},
+]
+"adafruit-platformdetect 3.24.1" = [
+    {file = "Adafruit-PlatformDetect-3.24.1.tar.gz", hash = "sha256:b2b339557d105d930b9989aa2adb5c07c5bca0c946cfae1ee9d421d38390abc4"},
+]
+"adafruit-pureio 1.1.9" = [
+    {file = "Adafruit_PureIO-1.1.9.tar.gz", hash = "sha256:2caf22fb07c7f771d83267f331a76cde314723f884a9570ea6f768730c87a879"},
+]
+"asyncio-mqtt 0.12.1" = [
+    {file = "asyncio_mqtt-0.12.1-py3-none-any.whl", hash = "sha256:cfa32fbd3a2d727ac74fa17ccafd30830a2a66f9e5e6ac7eee5458a9c7a6a832"},
+    {file = "asyncio_mqtt-0.12.1.tar.gz", hash = "sha256:6dbf85a45f94d26e7465411680ada3947b50546e98208d5d52e7a0a7ed7a7c38"},
+]
+"bandit 1.7.4" = [
+    {file = "bandit-1.7.4-py3-none-any.whl", hash = "sha256:412d3f259dab4077d0e7f0c11f50f650cc7d10db905d98f6520a95a18049658a"},
+    {file = "bandit-1.7.4.tar.gz", hash = "sha256:2d63a8c573417bae338962d4b9b06fbc6080f74ecd955a092849e1e65c717bd2"},
+]
+"black 22.3.0" = [
+    {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"},
+    {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"},
+    {file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"},
+    {file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"},
+    {file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"},
+    {file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"},
+    {file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"},
+    {file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"},
+    {file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"},
+    {file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"},
+    {file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"},
+    {file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"},
+    {file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"},
+    {file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"},
+    {file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"},
+    {file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"},
+    {file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"},
+    {file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"},
+    {file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"},
+    {file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"},
+    {file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"},
+    {file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"},
+    {file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"},
+]
+"cbor2 5.4.2" = [
+    {file = "cbor2-5.4.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:0153635a78e62d70f26f5b3469cb8de822420eda69c996304fb3d0dc1a53d7f3"},
+    {file = "cbor2-5.4.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70fb47a4bca70ae2d1b2b6c9d5ed6c898494739966653f7c84737f795b26d754"},
+    {file = "cbor2-5.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:10f178697e66eaae51534c3ef9acce1abf2f747e63c841e8702b9453c5bc4cfe"},
+    {file = "cbor2-5.4.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:4c112b21fad53b2d936ef2d55c698641a6d49025c1a9cf73db3ef24684514db1"},
+    {file = "cbor2-5.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93baf1ee33a305acf8f1391fed4e63ea2e837b561294fd6275ce8785acb795fa"},
+    {file = "cbor2-5.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:d9f64241bb30439f6ebde74101683e9dceecab95afe105560ac9d0e54d1b3c2e"},
+    {file = "cbor2-5.4.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:2757a7b624478d3b6707adf8ab7aef03d81fdaca6bea981b2323069660b9360f"},
+    {file = "cbor2-5.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32c1d00d8ad1a89f2358bf444fd43cacc3ca61f3c3feb1a2f2b2bea8ba4853d2"},
+    {file = "cbor2-5.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:79c10306d9128258dea110c01abbe9c58c48ee2ffcf995f982fb063f1a82e2ee"},
+    {file = "cbor2-5.4.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:0e27c52abdccadadab858437f6d98d5e8711aa84f0af7417dd1404d16127db7f"},
+    {file = "cbor2-5.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395aec8f415f039ab3be6cb58861c21bd2202f5c0ad6537b31956da532ea74ad"},
+    {file = "cbor2-5.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:310c7d7925f7aa6cb90791606be17c164bbf3b28d4d17047b5d19d303f2fe817"},
+    {file = "cbor2-5.4.2.tar.gz", hash = "sha256:e283e70b55a049ff364cc5e648fde587e4d9b0e87e4b2664c69e639135e6b3b8"},
+]
+"cerberus 1.3.4" = [
+    {file = "Cerberus-1.3.4.tar.gz", hash = "sha256:d1b21b3954b2498d9a79edf16b3170a3ac1021df88d197dc2ce5928ba519237c"},
+]
+"cfgv 3.3.1" = [
+    {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
+    {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
+]
+"click 8.1.3" = [
+    {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
+    {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
+]
+"colorama 0.4.5" = [
+    {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
+    {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
+]
+"colorlog 6.6.0" = [
+    {file = "colorlog-6.6.0-py2.py3-none-any.whl", hash = "sha256:351c51e866c86c3217f08e4b067a7974a678be78f07f85fc2d55b8babde6d94e"},
+    {file = "colorlog-6.6.0.tar.gz", hash = "sha256:344f73204009e4c83c5b6beb00b3c45dc70fcdae3c80db919e0a4171d006fde8"},
+]
+"deprecated 1.2.13" = [
+    {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"},
+    {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"},
+]
+"distlib 0.3.4" = [
+    {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"},
+    {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"},
+]
+"filelock 3.7.1" = [
+    {file = "filelock-3.7.1-py3-none-any.whl", hash = "sha256:37def7b658813cda163b56fc564cdc75e86d338246458c4c28ae84cabefa2404"},
+    {file = "filelock-3.7.1.tar.gz", hash = "sha256:3a0fd85166ad9dbab54c9aec96737b744106dc5f15c0b09a6744a445299fcf04"},
+]
+"flake8 4.0.1" = [
+    {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
+    {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
+]
+"gitdb 4.0.9" = [
+    {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"},
+    {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"},
+]
+"gitpython 3.1.27" = [
+    {file = "GitPython-3.1.27-py3-none-any.whl", hash = "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"},
+    {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"},
+]
+"gpio 0.3.0" = [
+    {file = "gpio-0.3.0.tar.gz", hash = "sha256:0b8db65f554ad7e6733910ead6560f9800d179a73a3e4e3413e619fc334f8c7b"},
+]
+"identify 2.5.1" = [
+    {file = "identify-2.5.1-py2.py3-none-any.whl", hash = "sha256:0dca2ea3e4381c435ef9c33ba100a78a9b40c0bab11189c7cf121f75815efeaa"},
+    {file = "identify-2.5.1.tar.gz", hash = "sha256:3d11b16f3fe19f52039fb7e39c9c884b21cb1b586988114fbe42671f03de3e82"},
+]
+"importlib-metadata 4.2.0" = [
+    {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"},
+    {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"},
+]
+"isort 5.10.1" = [
+    {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
+    {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
+]
+"luma.core 2.3.1" = [
+    {file = "luma.core-2.3.1-py2.py3-none-any.whl", hash = "sha256:407efa64351b91504de5399af782d54072dd8abe3a3fc79b05f2e9b2ad1816fb"},
+    {file = "luma.core-2.3.1.tar.gz", hash = "sha256:f293f5fff8946eea62af3a5d5d7da55c37d2b64aac6c9c90180a385da9f7d003"},
+]
+"luma.oled 3.8.1" = [
+    {file = "luma.oled-3.8.1-py2.py3-none-any.whl", hash = "sha256:e6a2947b51a0e3155ceb5defd7aa5377c2b853f9c663a300d8decd73c5e483a0"},
+    {file = "luma.oled-3.8.1.tar.gz", hash = "sha256:a9b445ecc686e9413ddac655544da21d801bbc6b94612736cf59283e6b92bcbb"},
+]
+"mccabe 0.6.1" = [
+    {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
+    {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
+]
+"mypy-extensions 0.4.3" = [
+    {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
+    {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
+]
+"nodeenv 1.6.0" = [
+    {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"},
+    {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"},
+]
+"paho-mqtt 1.6.1" = [
+    {file = "paho-mqtt-1.6.1.tar.gz", hash = "sha256:2a8291c81623aec00372b5a85558a372c747cbca8e9934dfe218638b8eefc26f"},
+]
+"pathspec 0.9.0" = [
+    {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
+    {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
+]
+"pbr 5.9.0" = [
+    {file = "pbr-5.9.0-py2.py3-none-any.whl", hash = "sha256:e547125940bcc052856ded43be8e101f63828c2d94239ffbe2b327ba3d5ccf0a"},
+    {file = "pbr-5.9.0.tar.gz", hash = "sha256:e8dca2f4b43560edef58813969f52a56cef023146cbb8931626db80e6c1c4308"},
+]
+"pillow 9.1.1" = [
+    {file = "Pillow-9.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:42dfefbef90eb67c10c45a73a9bc1599d4dac920f7dfcbf4ec6b80cb620757fe"},
+    {file = "Pillow-9.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffde4c6fabb52891d81606411cbfaf77756e3b561b566efd270b3ed3791fde4e"},
+    {file = "Pillow-9.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c857532c719fb30fafabd2371ce9b7031812ff3889d75273827633bca0c4602"},
+    {file = "Pillow-9.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59789a7d06c742e9d13b883d5e3569188c16acb02eeed2510fd3bfdbc1bd1530"},
+    {file = "Pillow-9.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d45dbe4b21a9679c3e8b3f7f4f42a45a7d3ddff8a4a16109dff0e1da30a35b2"},
+    {file = "Pillow-9.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e9ed59d1b6ee837f4515b9584f3d26cf0388b742a11ecdae0d9237a94505d03a"},
+    {file = "Pillow-9.1.1-cp310-cp310-win32.whl", hash = "sha256:b3fe2ff1e1715d4475d7e2c3e8dabd7c025f4410f79513b4ff2de3d51ce0fa9c"},
+    {file = "Pillow-9.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5b650dbbc0969a4e226d98a0b440c2f07a850896aed9266b6fedc0f7e7834108"},
+    {file = "Pillow-9.1.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:0b4d5ad2cd3a1f0d1df882d926b37dbb2ab6c823ae21d041b46910c8f8cd844b"},
+    {file = "Pillow-9.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9370d6744d379f2de5d7fa95cdbd3a4d92f0b0ef29609b4b1687f16bc197063d"},
+    {file = "Pillow-9.1.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b761727ed7d593e49671d1827044b942dd2f4caae6e51bab144d4accf8244a84"},
+    {file = "Pillow-9.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a66fe50386162df2da701b3722781cbe90ce043e7d53c1fd6bd801bca6b48d4"},
+    {file = "Pillow-9.1.1-cp37-cp37m-win32.whl", hash = "sha256:2b291cab8a888658d72b575a03e340509b6b050b62db1f5539dd5cd18fd50578"},
+    {file = "Pillow-9.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1d4331aeb12f6b3791911a6da82de72257a99ad99726ed6b63f481c0184b6fb9"},
+    {file = "Pillow-9.1.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8844217cdf66eabe39567118f229e275f0727e9195635a15e0e4b9227458daaf"},
+    {file = "Pillow-9.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b6617221ff08fbd3b7a811950b5c3f9367f6e941b86259843eab77c8e3d2b56b"},
+    {file = "Pillow-9.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20d514c989fa28e73a5adbddd7a171afa5824710d0ab06d4e1234195d2a2e546"},
+    {file = "Pillow-9.1.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:088df396b047477dd1bbc7de6e22f58400dae2f21310d9e2ec2933b2ef7dfa4f"},
+    {file = "Pillow-9.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53c27bd452e0f1bc4bfed07ceb235663a1df7c74df08e37fd6b03eb89454946a"},
+    {file = "Pillow-9.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3f6c1716c473ebd1649663bf3b42702d0d53e27af8b64642be0dd3598c761fb1"},
+    {file = "Pillow-9.1.1-cp38-cp38-win32.whl", hash = "sha256:c67db410508b9de9c4694c57ed754b65a460e4812126e87f5052ecf23a011a54"},
+    {file = "Pillow-9.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:f054b020c4d7e9786ae0404278ea318768eb123403b18453e28e47cdb7a0a4bf"},
+    {file = "Pillow-9.1.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:c17770a62a71718a74b7548098a74cd6880be16bcfff5f937f900ead90ca8e92"},
+    {file = "Pillow-9.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3f6a6034140e9e17e9abc175fc7a266a6e63652028e157750bd98e804a8ed9a"},
+    {file = "Pillow-9.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f372d0f08eff1475ef426344efe42493f71f377ec52237bf153c5713de987251"},
+    {file = "Pillow-9.1.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09e67ef6e430f90caa093528bd758b0616f8165e57ed8d8ce014ae32df6a831d"},
+    {file = "Pillow-9.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66daa16952d5bf0c9d5389c5e9df562922a59bd16d77e2a276e575d32e38afd1"},
+    {file = "Pillow-9.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d78ca526a559fb84faaaf84da2dd4addef5edb109db8b81677c0bb1aad342601"},
+    {file = "Pillow-9.1.1-cp39-cp39-win32.whl", hash = "sha256:55e74faf8359ddda43fee01bffbc5bd99d96ea508d8a08c527099e84eb708f45"},
+    {file = "Pillow-9.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c150dbbb4a94ea4825d1e5f2c5501af7141ea95825fadd7829f9b11c97aaf6c"},
+    {file = "Pillow-9.1.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:769a7f131a2f43752455cc72f9f7a093c3ff3856bf976c5fb53a59d0ccc704f6"},
+    {file = "Pillow-9.1.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:488f3383cf5159907d48d32957ac6f9ea85ccdcc296c14eca1a4e396ecc32098"},
+    {file = "Pillow-9.1.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b525a356680022b0af53385944026d3486fc8c013638cf9900eb87c866afb4c"},
+    {file = "Pillow-9.1.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6e760cf01259a1c0a50f3c845f9cad1af30577fd8b670339b1659c6d0e7a41dd"},
+    {file = "Pillow-9.1.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4165205a13b16a29e1ac57efeee6be2dfd5b5408122d59ef2145bc3239fa340"},
+    {file = "Pillow-9.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937a54e5694684f74dcbf6e24cc453bfc5b33940216ddd8f4cd8f0f79167f765"},
+    {file = "Pillow-9.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:baf3be0b9446a4083cc0c5bb9f9c964034be5374b5bc09757be89f5d2fa247b8"},
+    {file = "Pillow-9.1.1.tar.gz", hash = "sha256:7502539939b53d7565f3d11d87c78e7ec900d3c72945d4ee0e2f250d598309a0"},
+]
+"platformdirs 2.5.2" = [
+    {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"},
+    {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"},
+]
+"pre-commit 2.19.0" = [
+    {file = "pre_commit-2.19.0-py2.py3-none-any.whl", hash = "sha256:10c62741aa5704faea2ad69cb550ca78082efe5697d6f04e5710c3c229afdd10"},
+    {file = "pre_commit-2.19.0.tar.gz", hash = "sha256:4233a1e38621c87d9dda9808c6606d7e7ba0e087cd56d3fe03202a01d2919615"},
+]
+"psutil 5.9.1" = [
+    {file = "psutil-5.9.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:799759d809c31aab5fe4579e50addf84565e71c1dc9f1c31258f159ff70d3f87"},
+    {file = "psutil-5.9.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9272167b5f5fbfe16945be3db475b3ce8d792386907e673a209da686176552af"},
+    {file = "psutil-5.9.1-cp27-cp27m-win32.whl", hash = "sha256:0904727e0b0a038830b019551cf3204dd48ef5c6868adc776e06e93d615fc5fc"},
+    {file = "psutil-5.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e7e10454cb1ab62cc6ce776e1c135a64045a11ec4c6d254d3f7689c16eb3efd2"},
+    {file = "psutil-5.9.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:56960b9e8edcca1456f8c86a196f0c3d8e3e361320071c93378d41445ffd28b0"},
+    {file = "psutil-5.9.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:44d1826150d49ffd62035785a9e2c56afcea66e55b43b8b630d7706276e87f22"},
+    {file = "psutil-5.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7be9d7f5b0d206f0bbc3794b8e16fb7dbc53ec9e40bbe8787c6f2d38efcf6c9"},
+    {file = "psutil-5.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd9246e4cdd5b554a2ddd97c157e292ac11ef3e7af25ac56b08b455c829dca8"},
+    {file = "psutil-5.9.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29a442e25fab1f4d05e2655bb1b8ab6887981838d22effa2396d584b740194de"},
+    {file = "psutil-5.9.1-cp310-cp310-win32.whl", hash = "sha256:20b27771b077dcaa0de1de3ad52d22538fe101f9946d6dc7869e6f694f079329"},
+    {file = "psutil-5.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:58678bbadae12e0db55186dc58f2888839228ac9f41cc7848853539b70490021"},
+    {file = "psutil-5.9.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3a76ad658641172d9c6e593de6fe248ddde825b5866464c3b2ee26c35da9d237"},
+    {file = "psutil-5.9.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6a11e48cb93a5fa606306493f439b4aa7c56cb03fc9ace7f6bfa21aaf07c453"},
+    {file = "psutil-5.9.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:068935df39055bf27a29824b95c801c7a5130f118b806eee663cad28dca97685"},
+    {file = "psutil-5.9.1-cp36-cp36m-win32.whl", hash = "sha256:0f15a19a05f39a09327345bc279c1ba4a8cfb0172cc0d3c7f7d16c813b2e7d36"},
+    {file = "psutil-5.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:db417f0865f90bdc07fa30e1aadc69b6f4cad7f86324b02aa842034efe8d8c4d"},
+    {file = "psutil-5.9.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:91c7ff2a40c373d0cc9121d54bc5f31c4fa09c346528e6a08d1845bce5771ffc"},
+    {file = "psutil-5.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fea896b54f3a4ae6f790ac1d017101252c93f6fe075d0e7571543510f11d2676"},
+    {file = "psutil-5.9.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3054e923204b8e9c23a55b23b6df73a8089ae1d075cb0bf711d3e9da1724ded4"},
+    {file = "psutil-5.9.1-cp37-cp37m-win32.whl", hash = "sha256:d2d006286fbcb60f0b391741f520862e9b69f4019b4d738a2a45728c7e952f1b"},
+    {file = "psutil-5.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:b14ee12da9338f5e5b3a3ef7ca58b3cba30f5b66f7662159762932e6d0b8f680"},
+    {file = "psutil-5.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:19f36c16012ba9cfc742604df189f2f28d2720e23ff7d1e81602dbe066be9fd1"},
+    {file = "psutil-5.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:944c4b4b82dc4a1b805329c980f270f170fdc9945464223f2ec8e57563139cf4"},
+    {file = "psutil-5.9.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b6750a73a9c4a4e689490ccb862d53c7b976a2a35c4e1846d049dcc3f17d83b"},
+    {file = "psutil-5.9.1-cp38-cp38-win32.whl", hash = "sha256:a8746bfe4e8f659528c5c7e9af5090c5a7d252f32b2e859c584ef7d8efb1e689"},
+    {file = "psutil-5.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:79c9108d9aa7fa6fba6e668b61b82facc067a6b81517cab34d07a84aa89f3df0"},
+    {file = "psutil-5.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:28976df6c64ddd6320d281128817f32c29b539a52bdae5e192537bc338a9ec81"},
+    {file = "psutil-5.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b88f75005586131276634027f4219d06e0561292be8bd6bc7f2f00bdabd63c4e"},
+    {file = "psutil-5.9.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:645bd4f7bb5b8633803e0b6746ff1628724668681a434482546887d22c7a9537"},
+    {file = "psutil-5.9.1-cp39-cp39-win32.whl", hash = "sha256:32c52611756096ae91f5d1499fe6c53b86f4a9ada147ee42db4991ba1520e574"},
+    {file = "psutil-5.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:f65f9a46d984b8cd9b3750c2bdb419b2996895b005aefa6cbaba9a143b1ce2c5"},
+    {file = "psutil-5.9.1.tar.gz", hash = "sha256:57f1819b5d9e95cdfb0c881a8a5b7d542ed0b7c522d575706a80bedc848c8954"},
+]
+"pycodestyle 2.8.0" = [
+    {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
+    {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
+]
+"pyflakes 2.4.0" = [
+    {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"},
+    {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
+]
+"pyftdi 0.54.0" = [
+    {file = "pyftdi-0.54.0-py3-none-any.whl", hash = "sha256:112f16ee5b2a2becb8f8df9dd40b3bba007589f34e7613024122d94bd56eb7d7"},
+    {file = "pyftdi-0.54.0.tar.gz", hash = "sha256:8df9af22077d17533d2f95b508b1d87959877627ea5dc2369056e90a3b5a232d"},
+]
+"pymodbus 2.5.3" = [
+    {file = "pymodbus-2.5.3-py2.py3-none-any.whl", hash = "sha256:6f91403294a73b5a1616a11309f93c0b782115c09379438ef7ebc5bdf86182e9"},
+    {file = "pymodbus-2.5.3.tar.gz", hash = "sha256:5ef68c1a109bdb467c830ef003ef2db6494349a5248e4af946fe21c9eefe7e74"},
+]
+"pyserial 3.5" = [
+    {file = "pyserial-3.5-py2.py3-none-any.whl", hash = "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0"},
+    {file = "pyserial-3.5.tar.gz", hash = "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb"},
+]
+"pyserial-asyncio 0.6" = [
+    {file = "pyserial_asyncio-0.6-py3-none-any.whl", hash = "sha256:de9337922619421b62b9b1a84048634b3ac520e1d690a674ed246a2af7ce1fc5"},
+    {file = "pyserial-asyncio-0.6.tar.gz", hash = "sha256:b6032923e05e9d75ec17a5af9a98429c46d2839adfaf80604d52e0faacd7a32f"},
+]
+"pyusb 1.2.1" = [
+    {file = "pyusb-1.2.1-py3-none-any.whl", hash = "sha256:2b4c7cb86dbadf044dfb9d3a4ff69fd217013dbe78a792177a3feb172449ea36"},
+    {file = "pyusb-1.2.1.tar.gz", hash = "sha256:a4cc7404a203144754164b8b40994e2849fde1cfff06b08492f12fff9d9de7b9"},
+]
+"pyyaml 6.0" = [
+    {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
+    {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
+    {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
+    {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
+    {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
+    {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
+    {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
+    {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
+    {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
+    {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
+    {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
+    {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
+    {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
+    {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
+    {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
+    {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
+    {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
+    {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
+    {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
+    {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
+    {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
+    {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
+    {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
+    {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
+    {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
+    {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
+    {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
+    {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
+    {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
+    {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
+    {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
+    {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
+    {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
+]
+"rpi.gpio 0.7.1" = [
+    {file = "RPi.GPIO-0.7.1-cp27-cp27mu-linux_armv6l.whl", hash = "sha256:b86b66dc02faa5461b443a1e1f0c1d209d64ab5229696f32fb3b0215e0600c8c"},
+    {file = "RPi.GPIO-0.7.1-cp310-cp310-linux_armv6l.whl", hash = "sha256:57b6c044ef5375a78c8dda27cdfadf329e76aa6943cd6cffbbbd345a9adf9ca5"},
+    {file = "RPi.GPIO-0.7.1-cp37-cp37m-linux_armv6l.whl", hash = "sha256:77afb817b81331ce3049a4b8f94a85e41b7c404d8e56b61ac0f1eb75c3120868"},
+    {file = "RPi.GPIO-0.7.1-cp38-cp38-linux_armv6l.whl", hash = "sha256:29226823da8b5ccb9001d795a944f2e00924eeae583490f0bc7317581172c624"},
+    {file = "RPi.GPIO-0.7.1-cp39-cp39-linux_armv6l.whl", hash = "sha256:15311d3b063b71dee738cd26570effc9985a952454d162937c34e08c0fc99902"},
+    {file = "RPi.GPIO-0.7.1.tar.gz", hash = "sha256:cd61c4b03c37b62bba4a5acfea9862749c33c618e0295e7e90aa4713fb373b70"},
+]
+"setuptools 62.6.0" = [
+    {file = "setuptools-62.6.0-py3-none-any.whl", hash = "sha256:c1848f654aea2e3526d17fc3ce6aeaa5e7e24e66e645b5be2171f3f6b4e5a178"},
+    {file = "setuptools-62.6.0.tar.gz", hash = "sha256:990a4f7861b31532871ab72331e755b5f14efbe52d336ea7f6118144dd478741"},
+]
+"six 1.16.0" = [
+    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+"smbus2 0.4.2" = [
+    {file = "smbus2-0.4.2-py2.py3-none-any.whl", hash = "sha256:50f3c78e436b42a9583948be06961a8104cf020ebad5edfaaf2657528bef0818"},
+    {file = "smbus2-0.4.2.tar.gz", hash = "sha256:634541ed794068a822fe7499f1577468b9d4641b68dd9bfb6d0eb7270f4d2a32"},
+]
+"smmap 5.0.0" = [
+    {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"},
+    {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"},
+]
+"spidev 3.5" = [
+    {file = "spidev-3.5.tar.gz", hash = "sha256:8a7f5c289f161ea2ac4697fa8a10918232c990678dd0053084b3c43b1363910d"},
+]
+"stevedore 3.5.0" = [
+    {file = "stevedore-3.5.0-py3-none-any.whl", hash = "sha256:a547de73308fd7e90075bb4d301405bebf705292fa90a90fc3bcf9133f58616c"},
+    {file = "stevedore-3.5.0.tar.gz", hash = "sha256:f40253887d8712eaa2bb0ea3830374416736dc8ec0e22f5a65092c1174c44335"},
+]
+"toml 0.10.2" = [
+    {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
+    {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
+]
+"tomli 2.0.1" = [
+    {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
+    {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
+]
+"typed-ast 1.5.4" = [
+    {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"},
+    {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"},
+    {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"},
+    {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"},
+    {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"},
+    {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"},
+    {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"},
+    {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"},
+    {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"},
+    {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"},
+    {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"},
+    {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"},
+    {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"},
+    {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"},
+    {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"},
+    {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"},
+    {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"},
+    {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"},
+    {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"},
+    {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"},
+    {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"},
+    {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"},
+    {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"},
+    {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"},
+]
+"typing-extensions 4.2.0" = [
+    {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"},
+    {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"},
+]
+"virtualenv 20.14.1" = [
+    {file = "virtualenv-20.14.1-py2.py3-none-any.whl", hash = "sha256:e617f16e25b42eb4f6e74096b9c9e37713cf10bf30168fb4a739f3fa8f898a3a"},
+    {file = "virtualenv-20.14.1.tar.gz", hash = "sha256:ef589a79795589aada0c1c5b319486797c03b67ac3984c48c669c0e4f50df3a5"},
+]
+"wrapt 1.14.1" = [
+    {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"},
+    {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"},
+    {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"},
+    {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"},
+    {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"},
+    {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"},
+    {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"},
+    {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"},
+    {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"},
+    {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"},
+    {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"},
+    {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"},
+    {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"},
+    {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"},
+    {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"},
+    {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"},
+    {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"},
+    {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"},
+    {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"},
+    {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"},
+    {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"},
+    {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"},
+    {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"},
+    {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"},
+    {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"},
+    {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"},
+    {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"},
+    {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"},
+    {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"},
+    {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"},
+    {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"},
+    {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"},
+    {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"},
+    {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"},
+    {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"},
+    {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"},
+    {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"},
+    {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"},
+    {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"},
+    {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"},
+    {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"},
+    {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"},
+    {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"},
+    {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"},
+    {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"},
+    {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"},
+    {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"},
+    {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"},
+    {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"},
+    {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"},
+    {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"},
+    {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"},
+    {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"},
+    {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"},
+    {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"},
+    {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"},
+    {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"},
+    {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"},
+    {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"},
+    {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"},
+    {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"},
+    {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"},
+    {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"},
+    {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"},
+]
+"zipp 3.8.0" = [
+    {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"},
+    {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"},
+]
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..c150dd0
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,81 @@
+[project]
+name = "boneIO"
+description="Python App for BoneIO"
+readme = "README.md"
+dynamic = ["version"]
+authors = [
+    {name = "Paweł Szafer", email = "pszafer@gmail.com"},
+]
+dependencies = [
+    "Adafruit-Blinka>=8.0.2",
+    "adafruit-circuitpython-ds18x20>=1.3.12",
+    "adafruit-circuitpython-mcp230xx>=2.5.5",
+    "adafruit-circuitpython-mcp9808>=3.3.14",
+    "adafruit-circuitpython-pct2075>=1.1.14",
+    "asyncio-mqtt>=0.12.1",
+    "Cerberus>=1.3.4",
+    "colorlog>=6.6.0",
+    "gpio>=0.3.0",
+    "luma.core>=2.3.1",
+    "luma.oled>=3.8.1",
+    "pymodbus>=2.5.3",
+    "pyserial-asyncio>=0.6",
+    "PyYAML>=6.0",
+    "Adafruit-BBIO>=1.2.0",
+    "psutil>=5.9.1",
+]
+requires-python = ">=3.7"
+license = {text = "GNU General Public License v3.0"}
+
+[project.urls]
+Homepage = "https://boneio.eu"
+Repository = "https://github.com/boneIO-eu/app_bbb"
+Documentation = "https://boneio.eu/docs/intro/"
+Changelog = "https://github.com/boneIO-eu/app_bbb/releases"
+
+[project.scripts]
+boneio = "boneio.bonecli:main"
+
+[project.optional-dependencies]
+[tool.pdm]
+version = {from = "boneio/version.py"}
+[tool.pdm.dev-dependencies]
+dev = [
+    "black>=22.3.0",
+    "isort>=5.10.1",
+    "pre-commit>=2.19.0",
+    "flake8>=4.0.1",
+    "bandit>=1.7.4",
+]
+
+[build-system]
+requires = ["pdm-pep517"]
+build-backend = "pdm.pep517.api"
+
+[tool.black]
+line-length = 88
+exclude = '''
+/(
+    \.eggs
+  | \.git
+  | \.hg
+  | \.mypy_cache
+  | \.tox
+  | \.venv
+  | _build
+  | buck-out
+  | build
+  | dist
+  | pdm/_vendor
+  | tests/fixtures
+)/
+'''
+
+[tool.isort]
+profile = "black"
+atomic = true
+filter_files = true
+known_first_party = ["boneio"]
+
+[tool.pdm.scripts]
+lint = "pre-commit run --all-files"
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index f925fe5..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-Adafruit-BBIO==1.2.0
-Adafruit-Blinka==6.20.4
-adafruit-circuitpython-busdevice==5.1.4
-adafruit-circuitpython-ds18x20==1.3.10
-adafruit-circuitpython-mcp230xx==2.5.3
-adafruit-circuitpython-mcp9808==3.3.10
-adafruit-circuitpython-pct2075==1.1.12
-adafruit-circuitpython-register==1.9.8
-adafruit-circuitpython-busdevice==5.1.4
-Adafruit-PlatformDetect==3.19.5
-Adafruit-PureIO==1.1.9
-asyncio-mqtt==0.12.1
-cbor2==5.4.2.post1
-Cerberus==1.3.4
-click==8.0.3
-colorlog==6.6.0
-Deprecated==1.2.13
-gpio==0.3.0
-importlib-metadata==4.11.0
-luma.core==2.3.1
-luma.oled==3.8.1
-numpy==1.21.5
-paho-mqtt==1.6.1
-Pillow==9.0.1
-pkg_resources==0.0.0
-psutil==5.9.0
-pyaml==21.10.1
-pyftdi==0.53.3
-pymodbus==2.5.3
-pyserial==3.5
-pyserial-asyncio==0.6
-pyusb==1.2.1
-PyYAML==6.0
-rpi-ws281x==4.3.2
-six==1.16.0
-smbus2==0.4.1
-spidev==3.5
-sysv-ipc==1.1.0
-typing_extensions==4.1.0
-wrapt==1.13.3
-zipp==3.7.0
diff --git a/requirements_short.txt b/requirements_short.txt
deleted file mode 100644
index cf667bf..0000000
--- a/requirements_short.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-Adafruit-BBIO==1.2.0
-Adafruit-Blinka==6.20.4
-adafruit-circuitpython-busdevice==5.1.4
-adafruit-circuitpython-mcp230xx==2.5.3
-adafruit-circuitpython-mcp9808==3.3.10
-adafruit-circuitpython-pct2075==1.1.12
-adafruit-circuitpython-register==1.9.8
-adafruit-circuitpython-busdevice==5.1.4
-Adafruit-PlatformDetect==3.19.5
-Adafruit-PureIO==1.1.9
-asyncio-mqtt==0.12.1
-cbor2==5.4.2.post1
-Cerberus==1.3.4
-click==8.0.3
-colorlog==6.6.0
-Deprecated==1.2.13
-gpio==0.3.0
-importlib-metadata==4.11.0
-luma.core==2.3.1
-luma.oled==3.8.1
-numpy==1.21.5
-paho-mqtt==1.6.1
-Pillow==9.0.1
-psutil==5.9.0
-pyaml==21.10.1
-pyftdi==0.53.3
-pymodbus==2.5.3
-pyserial==3.5
-pyserial-asyncio==0.6
-pyusb==1.2.1
-PyYAML==6.0
-rpi-ws281x==4.3.2
-six==1.16.0
-smbus2==0.4.1
-spidev==3.5
-sysv-ipc==1.1.0
-typing_extensions==4.1.0
-wrapt==1.13.3
-zipp==3.7.0
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..c6feabc
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,22 @@
+# File for Flake8.
+
+[metadata]
+url = https://boneio.eu
+
+[flake8]
+exclude = .venv,.git,.tox,docs,venv,bin,lib,deps,build,tests/*
+max-complexity = 25
+doctests = True
+# To work with Black
+# E501: line too long
+# W503: Line break occurred before a binary operator
+# E203: Whitespace before ':'
+# D202 No blank lines allowed after function docstring
+# W504 line break after binary operator
+ignore =
+    E501,
+    W503,
+    E203,
+    D202,
+    W504
+noqa-require-code = True
diff --git a/setup.py b/setup.py
index e9e990e..27e84ec 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 # -*- coding:utf-8 -*-
-from setuptools import setup, find_packages
+from setuptools import find_packages, setup
 
 with open("README.md", "r") as fh:
     long_description = fh.read()


Test patch:
diff --git a/tests/bandit.yaml b/tests/bandit.yaml
new file mode 100644
index 0000000..568f77d
--- /dev/null
+++ b/tests/bandit.yaml
@@ -0,0 +1,21 @@
+# https://bandit.readthedocs.io/en/latest/config.html
+
+tests:
+  - B103
+  - B108
+  - B306
+  - B307
+  - B313
+  - B314
+  - B315
+  - B316
+  - B317
+  - B318
+  - B319
+  - B320
+  - B325
+  - B601
+  - B602
+  - B604
+  - B608
+  - B609
diff --git a/tests/relay_32_5.py b/tests/relay_32_5.py
index 65f53dc..ce4ad5b 100644
--- a/tests/relay_32_5.py
+++ b/tests/relay_32_5.py
@@ -1,16 +1,12 @@
 import asyncio
 import logging
-from boneio.manager import Manager
+
 from boneio.helper import load_config_from_file
+from boneio.manager import Manager
 
 _LOGGER = logging.getLogger(__name__)
 
-from boneio.const import (
-    MCP23017,
-    LM75,
-    MCP_TEMP_9808,
-    OUTPUT,
-)
+from boneio.const import LM75, MCP23017, MCP_TEMP_9808, OUTPUT
 
 
 async def test_32_5():