Skip to content
Merged

Pro+ #2070

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions data/config/apache/apache-proplus.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# openwb-version:1
Listen 8080

<VirtualHost *:8080>
ProxyPreserveHost On

# Proxy for Pro:
ProxyPass / http://192.168.192.50:80/
ProxyPassReverse / http://192.168.192.50:80/

ServerName localhost
</VirtualHost>
8 changes: 8 additions & 0 deletions data/config/dhcpcd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# openwb - begin
# openwb-version:1
# second interface connected to internal pro
interface eth1
static ip_address=192.168.192.150
# static routers=192.168.192.150
# static domain_name_servers=8.8.8.8
# openwb - end
9 changes: 9 additions & 0 deletions data/config/dnsmasq.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# openwb-version:1
# activate DHCP-Server on second interface only
interface=eth1

# IPv4 pool and lease time
dhcp-range=192.168.192.50,192.168.192.50,24h

# DNS
dhcp-option=option:dns-server,192.168.192.150
2 changes: 1 addition & 1 deletion packages/helpermodules/utils/error_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __exit__(self, exception_type, exception, exception_traceback) -> bool:
Pub().pub(self.topic, self.error_timestamp)
log.error(exception)
if self.hide_exception is False or timecheck.check_timestamp(self.error_timestamp, self.timeout) is False:
raise exception
return False
return True

def error_counter_exceeded(self) -> bool:
Expand Down
3 changes: 2 additions & 1 deletion packages/modules/chargepoints/internal_openwb/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@


class InternalChargepointMode(Enum):
SOCKET = "socket"
DUO = "duo"
PRO_PLUS = "pro_plus"
SERIES = "series"
SOCKET = "socket"


class InternalOpenWBConfiguration:
Expand Down
104 changes: 59 additions & 45 deletions packages/modules/chargepoints/openwb_pro/chargepoint_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ def __init__(self, config: OpenWBPro) -> None:
'http://' + self.config.configuration.ip_address + '/connect.php',
data={'heartbeatenabled': '1'})

def set_internal_context_handlers(self, parent_cp, parent_hostname):
self.fault_state = FaultState(ComponentInfo(
parent_cp,
"Ladepunkt "+str(self.config.id),
"chargepoint",
parent_id=parent_cp,
parent_hostname=parent_hostname))
self.client_error_context = ErrorTimerContext(
f"openWB/set/internal_chargepoint/{self.config.id}/get/error_timestamp", CP_ERROR, hide_exception=True)

def set_current(self, current: float) -> None:
if self.client_error_context.error_counter_exceeded():
current = 0
Expand All @@ -47,51 +57,55 @@ def set_current(self, current: float) -> None:

def get_values(self) -> None:
with SingleComponentUpdateContext(self.fault_state):
with self.client_error_context:
ip_address = self.config.configuration.ip_address
json_rsp = self.__session.get('http://'+ip_address+'/connect.php').json()

chargepoint_state = ChargepointState(
power=json_rsp["power_all"],
powers=json_rsp["powers"],
currents=json_rsp["currents"],
imported=json_rsp["imported"],
exported=json_rsp["exported"],
plug_state=json_rsp["plug_state"],
charge_state=json_rsp["charge_state"],
phases_in_use=json_rsp["phases_in_use"],
vehicle_id=json_rsp["vehicle_id"],
evse_current=json_rsp["offered_current"],
serial_number=json_rsp["serial"]
)

if json_rsp.get("voltages"):
meter_msg = check_meter_values(json_rsp["voltages"])
if meter_msg:
self.fault_state.warning(meter_msg)
chargepoint_state.voltages = json_rsp["voltages"]
if json_rsp.get("soc_value"):
chargepoint_state.soc = json_rsp["soc_value"]
if json_rsp.get("soc_timestamp"):
chargepoint_state.soc_timestamp = json_rsp["soc_timestamp"]
if json_rsp.get("frequency"):
chargepoint_state.frequency = json_rsp["frequency"]
if json_rsp.get("rfid_tag"):
chargepoint_state.rfid = json_rsp["rfid_tag"]
if json_rsp.get("rfid_timestamp"):
chargepoint_state.rfid_timestamp = json_rsp["rfid_timestamp"]

self.validate_values(chargepoint_state)
self.store.set(chargepoint_state)
self.old_chargepoint_state = chargepoint_state
self.client_error_context.reset_error_counter()
if self.client_error_context.error_counter_exceeded():
chargepoint_state = ChargepointState()
chargepoint_state.plug_state = False
chargepoint_state.charge_state = False
chargepoint_state.imported = self.old_chargepoint_state.imported
chargepoint_state.exported = self.old_chargepoint_state.exported
self.store.set(chargepoint_state)
chargepoint_state = self.request_values()
self.store.set(chargepoint_state)

def request_values(self) -> None:
with self.client_error_context:
chargepoint_state = self.old_chargepoint_state
ip_address = self.config.configuration.ip_address
json_rsp = self.__session.get('http://'+ip_address+'/connect.php').json()

chargepoint_state = ChargepointState(
power=json_rsp["power_all"],
powers=json_rsp["powers"],
currents=json_rsp["currents"],
imported=json_rsp["imported"],
exported=json_rsp["exported"],
plug_state=json_rsp["plug_state"],
charge_state=json_rsp["charge_state"],
phases_in_use=json_rsp["phases_in_use"],
vehicle_id=json_rsp["vehicle_id"],
evse_current=json_rsp["offered_current"],
serial_number=json_rsp["serial"]
)

if json_rsp.get("voltages"):
meter_msg = check_meter_values(json_rsp["voltages"])
if meter_msg:
self.fault_state.warning(meter_msg)
chargepoint_state.voltages = json_rsp["voltages"]
if json_rsp.get("soc_value"):
chargepoint_state.soc = json_rsp["soc_value"]
if json_rsp.get("soc_timestamp"):
chargepoint_state.soc_timestamp = json_rsp["soc_timestamp"]
if json_rsp.get("frequency"):
chargepoint_state.frequency = json_rsp["frequency"]
if json_rsp.get("rfid_tag"):
chargepoint_state.rfid = json_rsp["rfid_tag"]
if json_rsp.get("rfid_timestamp"):
chargepoint_state.rfid_timestamp = json_rsp["rfid_timestamp"]

self.validate_values(chargepoint_state)
self.old_chargepoint_state = chargepoint_state
self.client_error_context.reset_error_counter()
if self.client_error_context.error_counter_exceeded():
chargepoint_state = ChargepointState()
chargepoint_state.plug_state = False
chargepoint_state.charge_state = False
chargepoint_state.imported = self.old_chargepoint_state.imported
chargepoint_state.exported = self.old_chargepoint_state.exported
return chargepoint_state

def validate_values(self, chargepoint_state: ChargepointState) -> None:
if chargepoint_state.charge_state is False and max(chargepoint_state.currents) > 1:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ def sample_wrong_charge_state():
sample_wrong_charge_state = sample()
sample_wrong_charge_state.update({'charge_state': False,
'currents': [0, 2, 0],
'power_all': 0,
'date': '2023:01:30-18:48:31',
'evse_signaling': 'fake'})
return sample_wrong_charge_state
Expand All @@ -160,9 +161,10 @@ def sample_chargepoint_state_resetted():
pytest.param(sample(), 1652683242, None, None, sample_chargepoint_state(),
id="Timestamp gesetzt, kein Fehler aufgetreten"),
pytest.param(sample_wrong_charge_state(), None, None, 1652683252,
None, id="kein Timestamp gesetzt, Fehler aufgetreten"),
sample_wrong_charge_state_chargepoint_state(), id="kein Timestamp gesetzt, Fehler aufgetreten"),
pytest.param(sample_wrong_charge_state(), 1652683242, None, 1652683242,
None, id="Timestamp gesetzt, Fehler aufgetreten, Timestamp nicht abgelaufen"),
sample_wrong_charge_state_chargepoint_state(),
id="Timestamp gesetzt, Fehler aufgetreten, Timestamp nicht abgelaufen"),
pytest.param(sample_wrong_charge_state(), 1652683182, ValueError, 1652683182,
sample_chargepoint_state_resetted(),
id="Timestamp gesetzt, Fehler aufgetreten, Timestamp abgelaufen"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import logging

import time
from typing import Tuple
from helpermodules.logger import ModifyLoglevelContext

from modules.common.abstract_chargepoint import AbstractChargepoint
Expand Down Expand Up @@ -56,7 +55,7 @@ def set_current(self, current: float) -> None:
if self.set_current_evse != formatted_current:
self._client.evse_client.set_current(formatted_current)

def get_values(self, phase_switch_cp_active: bool, last_tag: str) -> Tuple[ChargepointState, float]:
def get_values(self, phase_switch_cp_active: bool, last_tag: str) -> ChargepointState:
def store_state(chargepoint_state: ChargepointState) -> None:
self.store.set(chargepoint_state)
self.store.update()
Expand Down Expand Up @@ -130,7 +129,7 @@ def store_state(chargepoint_state: ChargepointState) -> None:

store_state(chargepoint_state)
self.old_chargepoint_state = chargepoint_state
return chargepoint_state, self.set_current_evse
return chargepoint_state

def perform_phase_switch(self, phases_to_use: int, duration: int) -> None:
gpio_cp, gpio_relay = self._client.get_pins_phase_switch(phases_to_use)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from modules.common.component_state import ChargepointState
from modules.internal_chargepoint_handler import chargepoint_module
from modules.internal_chargepoint_handler.clients import ClientHandler, client_factory
from modules.internal_chargepoint_handler.pro_plus import ProPlus
from modules.internal_chargepoint_handler.socket import Socket
from modules.internal_chargepoint_handler.internal_chargepoint_handler_config import (
GlobalHandlerData, InternalChargepoint, InternalChargepointData, RfidData)
Expand Down Expand Up @@ -156,7 +157,10 @@ def __init__(self,
try:
with SingleComponentUpdateContext(self.fault_state_info_cp0, reraise=True):
# Allgemeine Fehlermeldungen an LP 1:
self.cp0_client_handler = client_factory(0, self.fault_state_info_cp0)
if mode == InternalChargepointMode.PRO_PLUS.value:
self.cp0_client_handler = None
else:
self.cp0_client_handler = client_factory(0, self.fault_state_info_cp0)
self.cp0 = HandlerChargepoint(self.cp0_client_handler, 0, mode,
global_data, parent_cp0, hierarchy_id_cp0)
except Exception:
Expand Down Expand Up @@ -208,7 +212,9 @@ def _loop():
time.sleep(1.1)
with SingleComponentUpdateContext(self.fault_state_info_cp0, update_always=False):
# Allgemeine Fehlermeldungen an LP 1
if self.cp0_client_handler is None and self.cp1_client_handler is None:
if self.cp0.mode == InternalChargepointMode.PRO_PLUS.value:
_loop()
elif self.cp0_client_handler is None and self.cp1_client_handler is None:
log.error("Kein ClientHandler vorhanden. Beende.")
elif self.cp0_client_handler is not None and self.cp1_client_handler is None:
with self.cp0_client_handler.client:
Expand All @@ -229,17 +235,20 @@ def _loop():

class HandlerChargepoint:
def __init__(self,
client_handler: ClientHandler,
client_handler: Optional[ClientHandler],
local_charge_point_num: int,
mode: InternalChargepointMode,
global_data: GlobalHandlerData,
parent_cp: str,
hierarchy_id: int) -> None:
self.local_charge_point_num = local_charge_point_num
self.mode = mode
if local_charge_point_num == 0:
if mode == InternalChargepointMode.SOCKET.value:
self.module = Socket(local_charge_point_num, client_handler,
global_data.parent_ip, parent_cp, hierarchy_id)
elif mode == InternalChargepointMode.PRO_PLUS.value:
self.module = ProPlus(local_charge_point_num, global_data.parent_ip, parent_cp, hierarchy_id)
else:
self.module = chargepoint_module.ChargepointModule(
local_charge_point_num, client_handler, global_data.parent_ip, parent_cp, hierarchy_id)
Expand All @@ -262,7 +271,7 @@ def __thread_active(thread: Optional[threading.Thread]) -> bool:
time.sleep(0.1)
phase_switch_cp_active = __thread_active(self.update_state.cp_interruption_thread) or __thread_active(
self.update_state.phase_switch_thread)
state = self.module.get_values(phase_switch_cp_active, rfid_data.last_tag)[0]
state = self.module.get_values(phase_switch_cp_active, rfid_data.last_tag)
log.debug("Published plug state "+str(state.plug_state))
heartbeat_expired = self._check_heartbeat_expired(global_data.heartbeat)
if global_data.parent_ip is not None:
Expand Down
40 changes: 40 additions & 0 deletions packages/modules/internal_chargepoint_handler/pro_plus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import requests
from modules.chargepoints.openwb_pro.chargepoint_module import ChargepointModule
from modules.chargepoints.openwb_pro.config import OpenWBPro, OpenWBProConfiguration
from modules.common.component_state import ChargepointState
from modules.common.store._chargepoint import get_chargepoint_value_store
from modules.common.store._chargepoint_internal import get_internal_chargepoint_value_store


class ProPlus(ChargepointModule):
def __init__(self, local_charge_point_num: int,
parent_hostname: str,
parent_cp: int,
hierarchy_id: int) -> None:
self.local_charge_point_num = local_charge_point_num
self.store_internal = get_internal_chargepoint_value_store(local_charge_point_num)
self.store = get_chargepoint_value_store(hierarchy_id)

super().__init__(OpenWBPro(configuration=OpenWBProConfiguration(ip_address="192.168.192.50")))
super().set_internal_context_handlers(parent_cp, parent_hostname)

def get_values(self, phase_switch_cp_active: bool, last_tag: str) -> ChargepointState:
def store_state(chargepoint_state: ChargepointState) -> None:
self.store.set(chargepoint_state)
self.store.update()
self.store_internal.set(chargepoint_state)
self.store_internal.update()

try:
chargepoint_state = super().request_values()
except (requests.exceptions.ConnectTimeout, requests.exceptions.ConnectionError):
raise Exception("Interner Ladepunkt ist nicht erreichbar.")

store_state(chargepoint_state)
return chargepoint_state

def perform_phase_switch(self, phases_to_use: int, duration: int) -> None:
super().switch_phases(phases_to_use, duration)

def perform_cp_interruption(self, duration: int) -> None:
pass
8 changes: 4 additions & 4 deletions packages/modules/internal_chargepoint_handler/socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import functools
import logging
import time
from typing import Callable, Tuple
from typing import Callable
from helpermodules.hardware_configuration import get_hardware_configuration_setting

from modules.common.component_context import SingleComponentUpdateContext
Expand Down Expand Up @@ -70,22 +70,22 @@ def set_current(self, current: float) -> None:
current = 0
super().set_current(min(current, self.socket_max_current))

def get_values(self, phase_switch_cp_active: bool, last_tag: str) -> Tuple[ChargepointState, float]:
def get_values(self, phase_switch_cp_active: bool, last_tag: str) -> ChargepointState:
try:
actor = ActorState(GPIO.input(19))
except Exception:
log.error("Error getting actor status! Using default 'opened'.")
actor = ActorState.OPENED
log.debug("Actor: "+str(actor))
self.chargepoint_state, self.set_current_evse = super().get_values(phase_switch_cp_active, last_tag)
self.chargepoint_state = super().get_values(phase_switch_cp_active, last_tag)
if phase_switch_cp_active:
log.debug("Keine Actor-Bewegung, da CP-Unterbrechung oder Phasenumschaltung aktiv.")
else:
if self.chargepoint_state.plug_state is True and actor == ActorState.OPENED:
self.__close_actor()
if self.chargepoint_state.plug_state is False and actor == ActorState.CLOSED:
self.__open_actor()
return self.chargepoint_state, self.set_current_evse
return self.chargepoint_state

def __open_actor(self):
self.__set_actor(open=True)
Expand Down
21 changes: 21 additions & 0 deletions runs/setup_apache2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ updateFile "${OPENWBBASEDIR}/data/config/apache/apache-openwb-ssl.conf" "/etc/ap
# http api site (https only)
echo "apache http api ssl site..."
updateFile "${OPENWBBASEDIR}/data/config/apache/http-api-ssl.conf" "/etc/apache2/sites-available/http-api-ssl.conf"
# proplus site
echo "apache pro plus site..."
updateFile "${OPENWBBASEDIR}/data/config/apache/apache-proplus.conf" "/etc/apache2/sites-available/apache-proplus.conf"

# disable apache default ssl site
disableSite default-ssl
Expand All @@ -98,6 +101,24 @@ else
disableSite http-api-ssl
fi

# check for pro+
echo "Pro+ setup..."
if lsusb | grep -q 'RTL8153'; then
echo "second network for pro plus detected"
# enable pro+ specific configurations
enableModule proxy_http
# enableModule proxy_fcgi
# enableModule proxy_ajp
enableSite apache-proplus
else
echo "no second network for pro plus detected"
# disable all pro+ specific configurations
disableModule proxy_http
# disableModule proxy_fcgi
# disableModule proxy_ajp
disableSite apache-proplus
fi

# restart apache if required
if ((restartService == 1)); then
echo -n "restarting apache..."
Expand Down
Loading