Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for Algodue UEM meters on CP0 and CP1 and as EVU-Kit #1960

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
98 changes: 98 additions & 0 deletions packages/modules/common/algodue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/usr/bin/env python3
import logging
from typing import List, Tuple, Optional

dj3mu marked this conversation as resolved.
Show resolved Hide resolved
from modules.common import modbus
from modules.common.abstract_counter import AbstractCounter
from modules.common.modbus import ModbusDataType

log = logging.getLogger(__name__)


class Algodue(AbstractCounter):
serial_cached: Optional[str] = None
model_cached: Optional[str] = None

def __init__(self, modbus_id: int, client: modbus.ModbusTcpClient_) -> None:
self.client = client
self.id = modbus_id

def get_imported(self) -> float:
return self.client.read_input_registers(0x1106, ModbusDataType.FLOAT_32, unit=self.id)

def get_exported(self) -> float:
return self.client.read_input_registers(0x110e, ModbusDataType.FLOAT_32, unit=self.id)

def get_frequency(self) -> float:
return self.client.read_input_registers(0x1038, ModbusDataType.FLOAT_32, unit=self.id)

def get_serial_number(self) -> Optional[str]:
# serial will never change - at least until power cycle
if self.serial_cached is not None:
return self.serial_cached

serial_chars = self.client.read_holding_registers(0x500, [ModbusDataType.UINT_8]*10, unit=self.id)
serial_string = ""
for x in serial_chars:
serial_string += chr(x)
# due to caching this appears rarely - but it's nice to have always have it in main log
log.error("Algodue meter serial " + serial_string)
self.serial_cached = serial_string
return self.serial_cached
dj3mu marked this conversation as resolved.
Show resolved Hide resolved

def get_currents(self) -> List[float]:
return self.client.read_input_registers(0x100E, [ModbusDataType.FLOAT_32]*3, unit=self.id)

def get_power_factors(self) -> List[float]:
return self.client.read_input_registers(0x1018, [ModbusDataType.FLOAT_32]*3, unit=self.id)

def get_power(self) -> Tuple[List[float], float]:
powers = self.client.read_input_registers(0x1020, [ModbusDataType.FLOAT_32]*3, unit=self.id)
power = sum(powers)
return powers, power

def get_voltages(self) -> List[float]:
return self.client.read_input_registers(0x1000, [ModbusDataType.FLOAT_32]*3, unit=self.id)

def get_model(self) -> Optional[str]:
# model will never change - at least until power cycle
if self.model_cached is not None:
return self.model_cached

model_id = self.client.read_holding_registers(0x505, ModbusDataType.UINT_16, unit=self.id)
model_string = "unknown"
if model_id == 0x03:
model_string = "6 A, 3 phases, 4 wires"
elif model_id == 0x08:
model_string = "80 A, 3 phases, 4 wires"
elif model_id == 0x0c:
model_string = "80 A, 1 phase, 2 wires"
elif model_id == 0x10:
model_string = "40 A, 1 phase, 2 wires"
elif model_id == 0x12:
model_string = "63 A, 3 phases, 4 wires"

type_id = self.client.read_holding_registers(0x506, ModbusDataType.UINT_16, unit=self.id)
type_string = "unknown"
if type_id == 0x00:
type_string = "NO MID, RESET"
elif type_id == 0x01:
type_string = "MID"
elif type_id == 0x02:
type_string = "NO MID"
elif type_id == 0x03:
type_string = "NO MID, Wiring selection"
elif type_id == 0x05:
type_string = "MID no varh"
elif type_id == 0x09:
type_string = "MID Wiring selection"
elif type_id == 0x0a:
type_string = "MID no varh, Wiring selection"
elif type_id == 0x0b:
type_string = "NO MID, RESET, Wiring selection"
meterinfo = "Algodue UEM " + model_string + ", " + type_string

# due to caching this appears rarely - but it's nice to have always have it in main log
log.error("Algodue model: " + meterinfo)
self.model_cached = meterinfo
return self.model_cached
dj3mu marked this conversation as resolved.
Show resolved Hide resolved
16 changes: 11 additions & 5 deletions packages/modules/internal_chargepoint_handler/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from modules.common.hardware_check import SeriesHardwareCheckMixin

from modules.common.modbus import ModbusSerialClient_, ModbusTcpClient_
from modules.common import mpm3pm, sdm
from modules.common import mpm3pm, sdm, algodue
from modules.common import evse
from modules.common import b23

Expand All @@ -15,13 +15,19 @@

BUS_SOURCES = ("/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyACM0", "/dev/serial0")

METERS = Union[mpm3pm.Mpm3pm, sdm.Sdm630_72, b23.B23]
METERS = Union[mpm3pm.Mpm3pm, sdm.Sdm630_72, b23.B23, algodue.Algodue]
meter_config = NamedTuple("meter_config", [('type', METERS), ('modbus_id', int)])

# Note: Algodue meters expect entry of modbus ID in hex. 9b = 155, 9c = 156.
# We code ID in hex here so it's exactly what must be entered in meter.
CP0_METERS = [meter_config(mpm3pm.Mpm3pm, modbus_id=5),
meter_config(sdm.Sdm630_72, modbus_id=105),
meter_config(b23.B23, modbus_id=201)]
meter_config(b23.B23, modbus_id=201),
meter_config(algodue.Algodue, modbus_id=0x9b)]

CP1_METERS = [meter_config(mpm3pm.Mpm3pm, modbus_id=6), meter_config(sdm.Sdm630_72, modbus_id=106)]
CP1_METERS = [meter_config(mpm3pm.Mpm3pm, modbus_id=6),
meter_config(sdm.Sdm630_72, modbus_id=106),
meter_config(algodue.Algodue, modbus_id=0x9c)]

EVSE_ID_CP0 = [1]
EVSE_ID_TWO_BUSSES_CP1 = [1, 2]
Expand Down Expand Up @@ -67,7 +73,7 @@ def find_meter_client(meters: List[meter_config], client: Union[ModbusSerialClie
try:
if meter_client.get_voltages()[0] > 200:
with ModifyLoglevelContext(log, logging.DEBUG):
log.debug("Verbauter Zähler: "+str(meter_type)+" mit Modbus-ID: "+str(modbus_id))
log.error("Verbauter Zähler: "+str(meter_type)+" mit Modbus-ID: "+str(modbus_id))
dj3mu marked this conversation as resolved.
Show resolved Hide resolved
return meter_client
except Exception:
log.debug(client)
Expand Down