Skip to content

Commit

Permalink
1.2.2:
Browse files Browse the repository at this point in the history
- Added option to specify baudrate, parity, stopbits and bytesize for each port
  • Loading branch information
spacemanspiff2007 committed Dec 21, 2022
1 parent 9f3bf4f commit 945c084
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 35 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
ref: master
- name: Set up Python 3.8
uses: actions/setup-python@v2
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: 3.8
python-version: 3.10

- name: Install setuptools
run: |
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/run_tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ jobs:
strategy:
max-parallel: 2
matrix:
python-version: ['3.8', '3.9', '3.10']
python-version: ['3.8', '3.9', '3.10', '3.11']

steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand Down
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
rev: v4.4.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace

- repo: https://github.com/pycqa/isort
rev: 5.8.0
rev: v5.11.3
hooks:
- id: isort
name: isort (python)

- repo: https://gitlab.com/PyCQA/flake8
rev: '3.9.1'
- repo: https://github.com/PyCQA/flake8
rev: '6.0.0'
hooks:
- id: flake8
4 changes: 2 additions & 2 deletions requirements_setup.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
asyncio-mqtt == 0.12.1
asyncio-mqtt == 0.16.1
pyserial-asyncio == 0.6
easyconfig == 0.2.4
easyconfig == 0.2.6
pydantic >= 1.10, <2.0
smllib == 1.2
2 changes: 1 addition & 1 deletion src/sml2mqtt/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ async def a_main():
try:
for port_cfg in CONFIG.ports:
dev_mqtt = BASE_TOPIC.create_child(port_cfg.url)
await Device.create(port_cfg.url, port_cfg.timeout, set(), dev_mqtt)
await Device.create(port_cfg, port_cfg.timeout, set(), dev_mqtt)

except Exception as e:
shutdown(e)
Expand Down
2 changes: 1 addition & 1 deletion src/sml2mqtt/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.2.1'
__version__ = '1.2.2'
41 changes: 39 additions & 2 deletions src/sml2mqtt/config/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from typing import Dict, List, Union

import serial
from easyconfig import AppBaseModel, BaseModel, create_app_config
from pydantic import constr, Field
from pydantic import constr, Field, StrictFloat, StrictInt, validator

from .device import REPUBLISH_ALIAS, SmlDeviceConfig, SmlValueConfig
from .logging import LoggingSettings
Expand All @@ -13,6 +14,42 @@ class PortSettings(BaseModel):
timeout: Union[int, float] = Field(
default=3, description='Seconds after which a timeout will be detected (default=3)')

baudrate: int = Field(9600, in_file=False)
parity: str = Field('None', in_file=False)
stopbits: Union[StrictInt, StrictFloat] = Field(serial.STOPBITS_ONE, in_file=False, alias='stop bits')
bytesize: int = Field(serial.EIGHTBITS, in_file=False, alias='byte size')

@validator('baudrate')
def _val_baudrate(cls, v):
if v not in serial.Serial.BAUDRATES:
raise ValueError(f'must be one of {list(serial.Serial.BAUDRATES)}')
return v

@validator('parity')
def _val_parity(cls, v):
# Short name
if v in serial.PARITY_NAMES:
return v

# Name -> Short name
parity_values = {_n: _v for _v, _n in serial.PARITY_NAMES.items()}
if v not in parity_values:
raise ValueError(f'must be one of {list(parity_values)}')
return parity_values[v]

@validator('stopbits')
def _val_stopbits(cls, v):
if v not in serial.Serial.STOPBITS:
raise ValueError(f'must be one of {list(serial.Serial.STOPBITS)}')
return v

@validator('bytesize')
def _val_bytesize(cls, v):
if v not in serial.Serial.BYTESIZES:
raise ValueError(f'must be one of {list(serial.Serial.BYTESIZES)}')
return v



class GeneralSettings(BaseModel):
wh_in_kwh: bool = Field(True, description='Automatically convert Wh to kWh', alias='Wh in kWh')
Expand Down Expand Up @@ -65,4 +102,4 @@ def default_config() -> Settings:
return s


CONFIG = create_app_config(Settings(), default_config)
CONFIG: Settings = create_app_config(Settings(), default_config)
9 changes: 5 additions & 4 deletions src/sml2mqtt/device/sml_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from sml2mqtt.__log__ import get_logger
from sml2mqtt.__shutdown__ import shutdown
from sml2mqtt.config import CONFIG
from sml2mqtt.config.config import PortSettings
from sml2mqtt.config.device import SmlDeviceConfig
from sml2mqtt.device import DeviceStatus
from sml2mqtt.device.watchdog import Watchdog
Expand All @@ -23,11 +24,11 @@

class Device:
@classmethod
async def create(cls, url: str, timeout: float, skip_values: Set[str], mqtt_device: MqttObj):
async def create(cls, settings: PortSettings, timeout: float, skip_values: Set[str], mqtt_device: MqttObj):
try:
device = cls(url, timeout, set(skip_values), mqtt_device)
device.serial = await sml2mqtt.device.SmlSerial.create(url, device)
ALL_DEVICES[url] = device
device = cls(settings.url, timeout, set(skip_values), mqtt_device)
device.serial = await sml2mqtt.device.SmlSerial.create(settings, device)
ALL_DEVICES[settings.url] = device
return device
except Exception as e:
raise DeviceSetupFailed(e) from None
Expand Down
10 changes: 7 additions & 3 deletions src/sml2mqtt/device/sml_serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from serial_asyncio import create_serial_connection, SerialTransport

from sml2mqtt.__log__ import get_logger
from sml2mqtt.config.config import PortSettings
from sml2mqtt.device import DeviceStatus

if TYPE_CHECKING:
Expand All @@ -16,11 +17,14 @@

class SmlSerial(asyncio.Protocol):
@classmethod
async def create(cls, url: str, device: 'sml2mqtt.device_id.Device') -> 'SmlSerial':
async def create(cls, settings: PortSettings, device: 'sml2mqtt.device_id.Device') -> 'SmlSerial':
transport, protocol = await create_serial_connection(
asyncio.get_event_loop(), cls, url, baudrate=9600) # type: SerialTransport, SmlSerial
asyncio.get_event_loop(), cls,
url=settings.url,
baudrate=settings.baudrate, parity=settings.parity,
stopbits=settings.stopbits, bytesize=settings.bytesize) # type: SerialTransport, SmlSerial

protocol.url = url
protocol.url = settings.url
protocol.device = device
return protocol

Expand Down
20 changes: 10 additions & 10 deletions tests/config/test_default.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,29 @@ def test_default():
Wh in kWh: true # Automatically convert Wh to kWh
republish after: 120 # Republish automatically after this time (if no other filter configured)
ports:
- url: COM1
timeout: 3
- url: /dev/ttyS0
timeout: 3
- url: COM1 # Device path
timeout: 3 # Seconds after which a timeout will be detected (default=3)
- url: /dev/ttyS0 # Device path
timeout: 3 # Seconds after which a timeout will be detected (default=3)
devices: # Device configuration by ID or url
DEVICE_ID_HEX:
mqtt:
topic: DEVICE_BASE_TOPIC
status:
topic: status
skip:
skip: # OBIS codes (HEX) of values that will not be published (optional)
- OBIS
values:
values: # Special configurations for each of the values (optional)
OBIS:
mqtt:
mqtt: # Mqtt config for this entry (optional)
topic: OBIS
workarounds:
workarounds: # Workarounds for the value (optional)
- negative on energy meter status: true
transformations:
transformations: # Mathematical transformations for the value (optional)
- factor: 3
- offset: 100
- round: 2
filters:
filters: # Refresh options for the value (optional)
- diff: 10
- perc: 10
- every: 120
Expand Down
3 changes: 2 additions & 1 deletion tests/device/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import sml2mqtt.device.sml_device
import sml2mqtt.device.sml_serial
from sml2mqtt.config.config import PortSettings
from sml2mqtt.device import Device, DeviceStatus
from sml2mqtt.mqtt import MqttObj

Expand All @@ -30,7 +31,7 @@ async def device(no_serial):
mqtt_base = MqttObj('testing', 0, False).update()
mqtt_device = mqtt_base.create_child(device_url)

obj = await Device.create(device_url, 1, set(), mqtt_device)
obj = await Device.create(PortSettings(url=device_url), 1, set(), mqtt_device)

# Wrapper so we see the traceback in the tests
def wrapper(func):
Expand Down

0 comments on commit 945c084

Please sign in to comment.