diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f4b6d51..b615718 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -23,7 +23,7 @@ repos: - id: detect-private-key - repo: https://github.com/editorconfig-checker/editorconfig-checker.python - rev: 2.3.54 + rev: 2.7.1 hooks: - id: editorconfig-checker args: @@ -35,16 +35,19 @@ repos: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.910-1 + rev: v1.2.0 hooks: - id: mypy + args: + - "--install-types" + - "--non-interactive" - repo: https://github.com/psf/black - rev: 21.10b0 + rev: 23.3.0 hooks: - id: black - repo: https://github.com/PyCQA/isort - rev: 5.9.3 + rev: 5.12.0 hooks: - id: isort diff --git a/Connector.md b/Connector.md index a880051..38562cb 100644 --- a/Connector.md +++ b/Connector.md @@ -1,7 +1,8 @@ # Connector -The connector is a RJ12 (6P6C, phone connector with all 6 positions populated) -The interface uses RS-232 levels (±15V) +The connector is a RJ12 (6P6C, phone connector with all 6 positions populated). +The interface uses RS-232 levels (±5V), make sure your adaptor can handle this! (Some adaptors require higher voltages). +TODO: Triple check RS-232 voltages. ## Pinout diff --git a/config-example.yaml b/config-example.yaml new file mode 100644 index 0000000..7aca723 --- /dev/null +++ b/config-example.yaml @@ -0,0 +1,12 @@ +consumers: + stdio.StdoutConsumer: {} +interface: + name: serial.SerialInterface + params: + port: /dev/ttyUSB0 + baudrate: 9600 + timeout: 2 +# name: feasycom.FeasycomInterface +# params: +# mac: DC:0D:30:9C:61:BA +# timeout: 5 diff --git a/misc/test_serial.py b/misc/test_serial.py new file mode 100644 index 0000000..7ea6505 --- /dev/null +++ b/misc/test_serial.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +import os +import sys +from time import sleep + +from serial import Serial + +print(sys.path) +sys.path.insert(1, os.path.dirname(os.path.dirname(sys.argv[0]))) +# from srnemqtt.constants import MAC +# from srnemqtt.lib.feasycom_ble import BTLEUart +from srnemqtt.protocol import construct_request, write # noqa: E402 + +for rate in [1200, 2400, 4800, 9600, 115200]: + print(rate) + with Serial("/dev/ttyUSB0", baudrate=rate, timeout=2) as x: + sleep(2) + + print(x) + + write(x, construct_request(0x0E, words=3)) + print(x.read(3)) + print(x.read(6)) + print(x.read(2)) + + # x.timeout = 2 + + # print(x.read()) + # print(x.read(1)) diff --git a/misc/test_serial_loopback.py b/misc/test_serial_loopback.py new file mode 100644 index 0000000..3351171 --- /dev/null +++ b/misc/test_serial_loopback.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +from serial import Serial + +with Serial("/dev/ttyUSB0", baudrate=9600, timeout=2) as x: + x.write(b"Hello, World!") + print(x.read(13)) + print(x.read(13)) diff --git a/requirements.txt b/requirements.txt index a12f1d1..5a919f0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,6 @@ rrdtool bluepy libscrc paho-mqtt +pyserial + +types-PyYAML diff --git a/srnemqtt/__main__.py b/srnemqtt/__main__.py index 70cb669..38d8058 100755 --- a/srnemqtt/__main__.py +++ b/srnemqtt/__main__.py @@ -5,28 +5,34 @@ import time from decimal import Decimal from typing import cast -from bluepy import btle +from bluepy.btle import BTLEDisconnectError +from serial import SerialException -from .config import get_config, get_consumers -from .constants import MAC -from .lib.feasycom_ble import BTLEUart +from .config import get_config, get_consumers, get_interface from .protocol import parse_battery_state, parse_historical_entry, try_read_parse from .solar_types import DataName from .util import Periodical, log +class CommunicationError(BTLEDisconnectError, SerialException, IOError): + pass + + def main(): conf = get_config() consumers = get_consumers(conf) per_voltages = Periodical(interval=15) per_current_hist = Periodical(interval=60) + # import serial + + # ser = serial.Serial() try: while True: try: log("Connecting...") - with BTLEUart(MAC, timeout=5) as dev: + with get_interface() as dev: log("Connected.") # write(dev, construct_request(0, 32)) @@ -96,7 +102,7 @@ def main(): # else: # write(wd, CMD_ENABLE_LOAD) - except btle.BTLEDisconnectError: + except CommunicationError: log("ERROR: Disconnected") time.sleep(1) diff --git a/srnemqtt/config.py b/srnemqtt/config.py index de435eb..4b3a4c1 100644 --- a/srnemqtt/config.py +++ b/srnemqtt/config.py @@ -6,6 +6,8 @@ from typing import Any, Dict, List, Optional, Type import yaml +from srnemqtt.interfaces import BaseInterface + from .consumers import BaseConsumer @@ -52,6 +54,30 @@ def get_consumers(conf: Optional[Dict[str, Any]] = None) -> List[BaseConsumer]: return consumers +def _get_interface(name: str) -> Type[BaseInterface]: + mod_name, cls_name = name.rsplit(".", 1) + + mod = importlib.import_module(f".interfaces.{mod_name}", package=__package__) + + res = getattr(mod, cls_name) + assert issubclass(res, BaseInterface) + + return res + + +def get_interface(conf: Optional[Dict[str, Any]] = None) -> BaseInterface: + if conf is None: + conf = get_config() + + name = conf["interface"]["name"] + params = conf["interface"].get("params", {}) + + mod = _get_interface(name) + assert mod + + return mod(**params) + + if __name__ == "__main__": conf = get_config() diff --git a/srnemqtt/interfaces/__init__.py b/srnemqtt/interfaces/__init__.py new file mode 100644 index 0000000..e8ecc37 --- /dev/null +++ b/srnemqtt/interfaces/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +from abc import ABCMeta +from io import RawIOBase + + +class BaseInterface(RawIOBase, metaclass=ABCMeta): + pass diff --git a/srnemqtt/interfaces/feasycom.py b/srnemqtt/interfaces/feasycom.py new file mode 100644 index 0000000..82a1172 --- /dev/null +++ b/srnemqtt/interfaces/feasycom.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +from ..lib.feasycom_ble import BTLEUart +from . import BaseInterface + + +class FeasycomInterface(BTLEUart, BaseInterface): + pass + + +# BTLEUart(mac=MAC, timeout=5) diff --git a/srnemqtt/interfaces/serial.py b/srnemqtt/interfaces/serial.py new file mode 100644 index 0000000..bee3ff6 --- /dev/null +++ b/srnemqtt/interfaces/serial.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +import serial + +from . import BaseInterface + + +class SerialInterface(serial.Serial, BaseInterface): + pass