integration Fronius ladestation mit ocpp.
This commit is contained in:
+132
-9
@@ -7,6 +7,7 @@ require_once __DIR__ . '/libs/OCPPFrameRouter.php';
|
||||
class OCPP_Server extends IPSModule
|
||||
{
|
||||
private const ATTR_CONNECTIONS = 'Connections';
|
||||
private const ATTR_OUTBOUND_QUEUES = 'OutboundQueues';
|
||||
|
||||
public function Create()
|
||||
{
|
||||
@@ -20,6 +21,7 @@ class OCPP_Server extends IPSModule
|
||||
$this->RegisterPropertyInteger('DebugLevel', 0);
|
||||
|
||||
$this->RegisterAttributeString(self::ATTR_CONNECTIONS, ConnectionRegistry::toJson(ConnectionRegistry::empty()));
|
||||
$this->RegisterAttributeString(self::ATTR_OUTBOUND_QUEUES, json_encode([]));
|
||||
|
||||
$this->RegisterVariableString('TransportStatus', 'TransportStatus', '', 10);
|
||||
$this->RegisterVariableString('LastInboundFrame', 'LastInboundFrame', '', 20);
|
||||
@@ -27,6 +29,7 @@ class OCPP_Server extends IPSModule
|
||||
$this->RegisterVariableString('LastRouteResult', 'LastRouteResult', '', 22);
|
||||
$this->RegisterVariableInteger('ConnectionCount', 'ConnectionCount', '', 30);
|
||||
$this->RegisterVariableInteger('LastMessageTime', 'LastMessageTime', '', 31);
|
||||
$this->RegisterVariableInteger('OutboundQueueCount', 'OutboundQueueCount', '', 32);
|
||||
$this->RegisterVariableString('WebSocketSupportStatus', 'WebSocketSupportStatus', '', 40);
|
||||
$this->RegisterVariableString('LetzteMeldung', 'LetzteMeldung', '', 41);
|
||||
$this->RegisterVariableInteger('LetzteMeldungZeit', 'LetzteMeldungZeit', '', 42);
|
||||
@@ -51,6 +54,11 @@ class OCPP_Server extends IPSModule
|
||||
$this->tryRegisterHook();
|
||||
}
|
||||
|
||||
$defaultTarget = $this->ReadPropertyInteger('DefaultTargetInstance');
|
||||
if ($defaultTarget > 0) {
|
||||
$this->RegisterReference($defaultTarget);
|
||||
}
|
||||
|
||||
$this->SetStatus(102);
|
||||
}
|
||||
|
||||
@@ -69,6 +77,10 @@ class OCPP_Server extends IPSModule
|
||||
$this->RouteInboundFrame((string)$Value);
|
||||
break;
|
||||
|
||||
case 'DequeueOutboundFrame':
|
||||
$this->DequeueOutboundFrame((string)$Value);
|
||||
break;
|
||||
|
||||
case 'TransportWatchdog':
|
||||
$this->TransportWatchdog();
|
||||
break;
|
||||
@@ -77,6 +89,8 @@ class OCPP_Server extends IPSModule
|
||||
$this->SetValue('LastInboundFrame', '');
|
||||
$this->SetValue('LastOutboundFrame', '');
|
||||
$this->SetValue('LastRouteResult', '');
|
||||
$this->WriteAttributeString(self::ATTR_OUTBOUND_QUEUES, json_encode([]));
|
||||
$this->SetValue('OutboundQueueCount', 0);
|
||||
$this->setMessage('Puffer geloescht');
|
||||
break;
|
||||
|
||||
@@ -95,27 +109,42 @@ class OCPP_Server extends IPSModule
|
||||
$path = $_SERVER['REQUEST_URI'] ?? $this->ReadPropertyString('HookPath');
|
||||
$chargePointId = (new OCPPFrameRouter())->extractChargePointId((string)$path);
|
||||
|
||||
$this->RouteInboundFrame(json_encode([
|
||||
$responseFrame = $this->RouteInboundFrame(json_encode([
|
||||
'ChargePointId' => $chargePointId,
|
||||
'Frame' => $raw,
|
||||
'Remote' => ($_SERVER['REMOTE_ADDR'] ?? '') . ':' . ($_SERVER['REMOTE_PORT'] ?? '')
|
||||
]));
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode([
|
||||
'status' => 'accepted',
|
||||
'note' => 'OCPP transport scaffold. Produktiver WebSocket-Dauerbetrieb muss mit Station verifiziert werden.'
|
||||
]);
|
||||
if ($responseFrame !== '') {
|
||||
echo $responseFrame;
|
||||
return;
|
||||
}
|
||||
|
||||
echo json_encode(['status' => 'accepted']);
|
||||
}
|
||||
|
||||
public function QueueOutboundFrame(string $json): void
|
||||
{
|
||||
$this->SetValue('LastOutboundFrame', $json);
|
||||
$envelope = json_decode($json, true);
|
||||
if (!is_array($envelope)) {
|
||||
$envelope = [
|
||||
'ChargePointId' => '',
|
||||
'Frame' => $json,
|
||||
'Timestamp' => time()
|
||||
];
|
||||
}
|
||||
|
||||
$frame = (string)($envelope['Frame'] ?? $json);
|
||||
$chargePointId = (string)($envelope['ChargePointId'] ?? '');
|
||||
|
||||
$this->SetValue('LastOutboundFrame', $frame);
|
||||
$this->SetValue('LastMessageTime', time());
|
||||
$this->setMessage('Outbound Frame vorgemerkt. Aktiver WebSocket-Sendekanal ist noch Scaffold.');
|
||||
$this->enqueueOutboundFrame($chargePointId, $frame);
|
||||
$this->setMessage('Outbound Frame fuer ' . ($chargePointId === '' ? 'unbekannt' : $chargePointId) . ' gepuffert.');
|
||||
}
|
||||
|
||||
public function RouteInboundFrame(string $json): void
|
||||
public function RouteInboundFrame(string $json): string
|
||||
{
|
||||
$data = json_decode($json, true);
|
||||
if (!is_array($data)) {
|
||||
@@ -163,10 +192,58 @@ class OCPP_Server extends IPSModule
|
||||
if ($target > 0 && IPS_InstanceExists($target)) {
|
||||
IPS_RequestAction($target, 'HandleInboundFrame', $frame);
|
||||
$this->setMessage('Inbound Frame an Zielinstanz ' . $target . ' geroutet.');
|
||||
return;
|
||||
return $this->DequeueOutboundFrame($chargePointId, $this->extractUniqueId($frame));
|
||||
}
|
||||
|
||||
$this->setMessage('Inbound Frame empfangen, aber keine Zielinstanz gefunden.');
|
||||
return '';
|
||||
}
|
||||
|
||||
public function DequeueOutboundFrame(string $chargePointId = '', string $preferredUniqueId = ''): string
|
||||
{
|
||||
$queues = $this->readOutboundQueues();
|
||||
if ($preferredUniqueId !== '') {
|
||||
foreach ($queues as $candidateKey => $queue) {
|
||||
if (!is_array($queue)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($queue as $candidateIndex => $candidateFrame) {
|
||||
if ($this->isCallResultForUniqueId((string)$candidateFrame, $preferredUniqueId)) {
|
||||
$frame = (string)$candidateFrame;
|
||||
array_splice($queues[$candidateKey], (int)$candidateIndex, 1);
|
||||
if (empty($queues[$candidateKey])) {
|
||||
unset($queues[$candidateKey]);
|
||||
}
|
||||
$this->WriteAttributeString(self::ATTR_OUTBOUND_QUEUES, json_encode($queues));
|
||||
$this->SetValue('OutboundQueueCount', $this->countOutboundFrames($queues));
|
||||
return $frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$key = $chargePointId;
|
||||
if ($key === '' || !isset($queues[$key]) || empty($queues[$key])) {
|
||||
foreach ($queues as $candidate => $queue) {
|
||||
if (!empty($queue)) {
|
||||
$key = (string)$candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($key === '' || !isset($queues[$key]) || empty($queues[$key])) {
|
||||
$this->SetValue('OutboundQueueCount', $this->countOutboundFrames($queues));
|
||||
return '';
|
||||
}
|
||||
|
||||
$frame = (string)array_shift($queues[$key]);
|
||||
if (empty($queues[$key])) {
|
||||
unset($queues[$key]);
|
||||
}
|
||||
$this->WriteAttributeString(self::ATTR_OUTBOUND_QUEUES, json_encode($queues));
|
||||
$this->SetValue('OutboundQueueCount', $this->countOutboundFrames($queues));
|
||||
return $frame;
|
||||
}
|
||||
|
||||
public function TransportWatchdog(): void
|
||||
@@ -215,6 +292,52 @@ class OCPP_Server extends IPSModule
|
||||
$this->SendDebug('OCPP_Server', $message, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private function enqueueOutboundFrame(string $chargePointId, string $frame): void
|
||||
{
|
||||
$key = $chargePointId === '' ? '_default' : $chargePointId;
|
||||
$queues = $this->readOutboundQueues();
|
||||
if (!isset($queues[$key]) || !is_array($queues[$key])) {
|
||||
$queues[$key] = [];
|
||||
}
|
||||
$queues[$key][] = $frame;
|
||||
$this->WriteAttributeString(self::ATTR_OUTBOUND_QUEUES, json_encode($queues));
|
||||
$this->SetValue('OutboundQueueCount', $this->countOutboundFrames($queues));
|
||||
}
|
||||
|
||||
private function readOutboundQueues(): array
|
||||
{
|
||||
$queues = json_decode($this->ReadAttributeString(self::ATTR_OUTBOUND_QUEUES), true);
|
||||
return is_array($queues) ? $queues : [];
|
||||
}
|
||||
|
||||
private function countOutboundFrames(array $queues): int
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($queues as $queue) {
|
||||
if (is_array($queue)) {
|
||||
$count += count($queue);
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
private function extractUniqueId(string $frame): string
|
||||
{
|
||||
$data = json_decode($frame, true);
|
||||
if (!is_array($data) || count($data) < 2) {
|
||||
return '';
|
||||
}
|
||||
return (string)$data[1];
|
||||
}
|
||||
|
||||
private function isCallResultForUniqueId(string $frame, string $uniqueId): bool
|
||||
{
|
||||
$data = json_decode($frame, true);
|
||||
return is_array($data)
|
||||
&& (int)($data[0] ?? 0) === 3
|
||||
&& (string)($data[1] ?? '') === $uniqueId;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user