Skip to content

Commit

Permalink
Merge pull request #29 from jedie/validating
Browse files Browse the repository at this point in the history
Fix #24 by validation "Radiator Temperature" and "Total AC Output Power (Active)"
  • Loading branch information
jedie committed May 6, 2023
2 parents d139b18 + b107181 commit 6d49b28
Show file tree
Hide file tree
Showing 23 changed files with 445 additions and 162 deletions.
48 changes: 30 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,17 @@ Usage: ./cli.py publish-loop [OPTIONS] IP
AT-command.
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮
│ --port INTEGER RANGE [1000<=x<=65535] Port of the inverter │
│ [default: 48899; 1000<=x<=65535] │
│ --log/--no-log [default: log] │
│ --verbose/--no-verbose [default: verbose] │
│ --debug/--no-debug [default: no-debug] │
│ --help Show this message and exit. │
│ * --port INTEGER RANGE [1000<=x<=65535] Port of the inverter │
│ [default: 48899; 1000<=x<=65535] │
│ [required] │
│ * --inverter TEXT Prefix of yaml config files in │
│ inverter/definitions/ │
│ [default: deye_2mppt] │
│ [required] │
│ --log/--no-log [default: log] │
│ --verbose/--no-verbose [default: verbose] │
│ --debug/--no-debug [default: no-debug] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
```
[comment]: <> (✂✂✂ auto generated publish-loop help end ✂✂✂)
Expand All @@ -90,10 +95,15 @@ Usage: ./cli.py print-values [OPTIONS] IP
.../inverter-connect$ ./cli.py print-values 192.168.123.456
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮
│ --port INTEGER RANGE [1000<=x<=65535] Port of the inverter │
│ [default: 48899; 1000<=x<=65535] │
│ --debug/--no-debug [default: no-debug] │
│ --help Show this message and exit. │
│ --port INTEGER RANGE [1000<=x<=65535] Port of the inverter │
│ [default: 48899; 1000<=x<=65535] │
│ * --inverter TEXT Prefix of yaml config files in │
│ inverter/definitions/ │
│ [default: deye_2mppt] │
│ [required] │
│ --verbose/--no-verbose [default: verbose] │
│ --debug/--no-debug [default: no-debug] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
```
[comment]: <> (✂✂✂ auto generated print-values help end ✂✂✂)
Expand Down Expand Up @@ -127,10 +137,11 @@ Usage: ./cli.py print-at-commands [OPTIONS] IP [COMMANDS]...
(Note: The prefix "AT+" will be added to every command)
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮
│ --port INTEGER RANGE [1000<=x<=65535] Port of the inverter │
│ [default: 48899; 1000<=x<=65535] │
│ --debug/--no-debug [default: no-debug] │
│ --help Show this message and exit. │
│ --port INTEGER RANGE [1000<=x<=65535] Port of the inverter │
│ [default: 48899; 1000<=x<=65535] │
│ --verbose/--no-verbose [default: verbose] │
│ --debug/--no-debug [default: no-debug] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
```
[comment]: <> (✂✂✂ auto generated print-at-commands help end ✂✂✂)
Expand Down Expand Up @@ -158,10 +169,11 @@ Usage: ./cli.py read-register [OPTIONS] IP REGISTER LENGTH
The start address can be pass as decimal number or as hex string, e.g.: 0x123
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮
│ --port INTEGER RANGE [1000<=x<=65535] Port of the inverter │
│ [default: 48899; 1000<=x<=65535] │
│ --debug/--no-debug [default: debug] │
│ --help Show this message and exit. │
│ --port INTEGER RANGE [1000<=x<=65535] Port of the inverter │
│ [default: 48899; 1000<=x<=65535] │
│ --verbose/--no-verbose [default: verbose] │
│ --debug/--no-debug [default: no-debug] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
```
[comment]: <> (✂✂✂ auto generated read-register help end ✂✂✂)
Expand Down
2 changes: 1 addition & 1 deletion inverter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
Get information from Deye Microinverter
"""

__version__ = '0.5.0'
__version__ = '0.6.0'
__author__ = 'Jens Diemer <inverter-connect@jensdiemer.de>'
37 changes: 16 additions & 21 deletions inverter/api.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,22 @@
from __future__ import annotations

import dataclasses
import logging
from collections.abc import Iterable
from datetime import datetime
from enum import Enum

from rich import print # noqa
from rich.pretty import pprint

from inverter.config import Config
from inverter.connection import InverterSock, ModbusReadResult
from inverter.connection import InverterSock
from inverter.data_types import Config, InverterValue, ModbusReadResult, ValueType
from inverter.definitions import get_parameter
from inverter.exceptions import ValidationError
from inverter.validators import InverterValueValidator


logger = logging.getLogger(__name__)


class ValueType(Enum):
READ_OUT = 'read out'
COMPUTED = 'computed'


@dataclasses.dataclass
class InverterValue:
type: ValueType
name: str
value: float | str
device_class: str # e.g.: "voltage" / "current" / "energy" etc.
state_class: str | None # e.g.: "measurement" / "total" / "total_increasing" etc.
unit: str # e.g.: "V" / "A" / "kWh" etc.
result: ModbusReadResult | None


def compute_values(values: dict) -> Iterable[InverterValue]:
total_power = None
for no in range(1, 10):
Expand Down Expand Up @@ -87,7 +72,8 @@ def compute_values(values: dict) -> Iterable[InverterValue]:
class Inverter:
def __init__(self, config: Config):
self.config = config
self.parameters = get_parameter(yaml_filename=config.yaml_filename, debug=config.debug)
self.parameters = get_parameter(config=config)
self.value_validator = InverterValueValidator(config=config)
self.inv_sock = InverterSock(config)

def __enter__(self):
Expand Down Expand Up @@ -119,6 +105,15 @@ def __iter__(self) -> Iterable[InverterValue]:
unit=parameter.unit,
result=result,
)
if self.config.debug:
pprint(value, indent_guides=False)

try:
self.value_validator(inverter_value=value)
except ValidationError as err:
logger.info(f'Validation error: {err}')
raise

assert name not in values, f'Double {name=}: {value=} - {values=}'
values[name] = value
yield value
Expand Down
52 changes: 34 additions & 18 deletions inverter/cli/cli_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@

import inverter
from inverter import constants
from inverter.api import Inverter, ValueType, set_current_time
from inverter.config import Config
from inverter.connection import InverterInfo, InverterSock
from inverter.api import Inverter, set_current_time
from inverter.connection import InverterSock
from inverter.constants import ERROR_STR_NO_DATA
from inverter.definitions import Parameter
from inverter.data_types import Config, InverterInfo, Parameter, ValueType
from inverter.mqtt4homeassistant.data_classes import MqttSettings
from inverter.mqtt4homeassistant.mqtt import get_connected_client
from inverter.publish_loop import publish_forever
Expand Down Expand Up @@ -53,6 +52,14 @@
type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True, path_type=Path)
)

INVERTER_NAME = dict(
required=True,
type=str,
default='deye_2mppt',
help='Prefix of yaml config files in inverter/definitions/',
show_default=True,
)


class ClickGroup(RichGroup): # FIXME: How to set the "info_name" easier?
def make_context(self, info_name, *args, **kwargs):
Expand Down Expand Up @@ -83,16 +90,18 @@ def version():
@click.option(
'--port', type=click.IntRange(1000, 65535), default=48899, help='Port of the inverter', show_default=True
)
@click.option('--inverter', **INVERTER_NAME)
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_TRUE)
@click.option('--debug/--no-debug', **OPTION_ARGS_DEFAULT_FALSE)
def print_values(ip, port, debug):
def print_values(ip, port, inverter, verbose, debug):
"""
Print all known register values from Inverter, e.g.:
.../inverter-connect$ ./cli.py print-values 192.168.123.456
"""
basic_log_setup(debug=debug)

config = Config(yaml_filename='deye_2mppt.yaml', host=ip, port=port, debug=debug)
config = Config(inverter_name=inverter, host=ip, port=port, verbose=verbose, debug=debug)
with Inverter(config=config) as inverter:
inverter_info: InverterInfo = inverter.inv_sock.inverter_info
print(inverter_info)
Expand Down Expand Up @@ -130,8 +139,9 @@ def print_values(ip, port, debug):
@click.option(
'--port', type=click.IntRange(1000, 65535), default=48899, help='Port of the inverter', show_default=True
)
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_TRUE)
@click.option('--debug/--no-debug', **OPTION_ARGS_DEFAULT_FALSE)
def print_at_commands(ip, port, commands, debug):
def print_at_commands(ip, port, commands, verbose, debug):
"""
Print one or more AT command values from Inverter.
Expand Down Expand Up @@ -201,7 +211,7 @@ def print_at_commands(ip, port, commands, debug):
'DEVSELCTL', # Set/Get Web Device List Info
)

config = Config(yaml_filename=None, host=ip, port=port, debug=debug)
config = Config(inverter_name=None, host=ip, port=port, verbose=verbose, debug=debug)
if debug:
print(config)

Expand All @@ -225,8 +235,9 @@ def print_at_commands(ip, port, commands, debug):
'--port', type=click.IntRange(1000, 65535), default=48899, help='Port of the inverter', show_default=True
)
@click.option('--register', default="0x16", help='Start address', show_default=True)
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_TRUE)
@click.option('--debug/--no-debug', **OPTION_ARGS_DEFAULT_TRUE)
def set_time(ip, port, register, debug):
def set_time(ip, port, register, verbose, debug):
"""
Set current date time in the inverter device.
Expand All @@ -237,7 +248,7 @@ def set_time(ip, port, register, debug):
"""
address = convert_address_option(raw_address=register, debug=debug)

config = Config(yaml_filename=None, host=ip, port=port, debug=debug)
config = Config(inverter_name=None, host=ip, port=port, verbose=verbose, debug=debug)
if debug:
print(config)

Expand Down Expand Up @@ -266,10 +277,11 @@ def set_time(ip, port, register, debug):
@click.option(
'--port', type=click.IntRange(1000, 65535), default=48899, help='Port of the inverter', show_default=True
)
@click.option('--debug/--no-debug', **OPTION_ARGS_DEFAULT_TRUE)
@click.argument('register')
@click.argument('length', type=click.IntRange(1, 100))
def read_register(ip, port, register, length, debug):
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_TRUE)
@click.option('--debug/--no-debug', **OPTION_ARGS_DEFAULT_FALSE)
def read_register(ip, port, register, length, verbose, debug):
"""
Read register(s) from the inverter
Expand All @@ -286,9 +298,7 @@ def read_register(ip, port, register, length, debug):
print(f'Read {length} register(s) from {register=!r} ({ip}:{port})')
address = convert_address_option(raw_address=register, debug=debug)

config = Config(yaml_filename=None, host=ip, port=port, debug=debug)
if debug:
print(config)
config = Config(inverter_name=None, host=ip, port=port, verbose=verbose, debug=debug)

with InverterSock(config) as inv_sock:
inverter_info: InverterInfo = inv_sock.inverter_info
Expand Down Expand Up @@ -380,12 +390,18 @@ def test_mqtt_connection(debug):
@click.command()
@click.argument('ip')
@click.option(
'--port', type=click.IntRange(1000, 65535), default=48899, help='Port of the inverter', show_default=True
'--port',
type=click.IntRange(1000, 65535),
default=48899,
help='Port of the inverter',
show_default=True,
required=True,
)
@click.option('--inverter', **INVERTER_NAME)
@click.option('--log/--no-log', **OPTION_ARGS_DEFAULT_TRUE)
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_TRUE)
@click.option('--debug/--no-debug', **OPTION_ARGS_DEFAULT_FALSE)
def publish_loop(ip, port, log, verbose, debug):
def publish_loop(ip, port, inverter, log, verbose, debug):
"""
Publish current data via MQTT for Home Assistant (endless loop)
Expand All @@ -395,7 +411,7 @@ def publish_loop(ip, port, log, verbose, debug):
if log:
basic_log_setup(debug=debug)

config = Config(yaml_filename='deye_2mppt.yaml', host=ip, port=port, debug=debug)
config = Config(inverter_name=inverter, host=ip, port=port, verbose=verbose, debug=debug)

mqtt_settings: MqttSettings = get_mqtt_settings()
pprint(mqtt_settings.anonymized())
Expand Down
22 changes: 0 additions & 22 deletions inverter/config.py

This file was deleted.

31 changes: 1 addition & 30 deletions inverter/connection.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,19 @@
from __future__ import annotations

import dataclasses
import logging
import socket
import time

from rich import print # noqa

from inverter.config import Config
from inverter.constants import AT_READ_FUNC_NUMBER, AT_WRITE_FUNC_NUMBER, ERROR_STR_NO_DATA
from inverter.definitions import Parameter
from inverter.data_types import Config, InverterInfo, ModbusReadResult, ModbusResponse, Parameter, RawModBusResponse
from inverter.exceptions import CrcError, ModbusNoData, ModbusNoHexData, ParseModbusValueError, ReadTimeout


logger = logging.getLogger(__name__)


@dataclasses.dataclass
class InverterInfo:
ip: str
mac: str
serial: int


@dataclasses.dataclass
class RawModBusResponse:
prefix: str
data: str


@dataclasses.dataclass
class ModbusResponse:
slave_id: int
modbus_function: int
data_hex: str


@dataclasses.dataclass
class ModbusReadResult:
parameter: Parameter
parsed_value: float | str
response: ModbusResponse = None


def make_modbus_result(*, response: ModbusResponse, parameter: Parameter) -> ModbusReadResult:
parser_func = parameter.parser
data_hex = response.data_hex
Expand Down
4 changes: 4 additions & 0 deletions inverter/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@
ERROR_STR_NO_DATA = 'no data'
AT_READ_FUNC_NUMBER = 0x03
AT_WRITE_FUNC_NUMBER = 0x10
TYPE_MAP = {
'float': float,
'int': int,
}

0 comments on commit 6d49b28

Please sign in to comment.