<?php

class MQTTBatterySDL extends IPSModule
{
    public function Create()
    {
        parent::Create();

        // Eigenschaften
        $this->RegisterPropertyString('TopicSuffix', '');

        $this->RegisterPropertyInteger('ReqActionID', 0);
        $this->RegisterPropertyInteger('SoCID', 0);
        $this->RegisterPropertyInteger('PowerProductionID', 0);

        $this->RegisterPropertyInteger('TargetSoC', 50);
        $this->RegisterPropertyInteger('ChargePower', 2500);
        $this->RegisterPropertyInteger('DischargePower', 2500);
        $this->RegisterPropertyInteger('MaxPowerSetpoint', 10000);

        // Variablen
        $this->RegisterVariableBoolean('IsReady', 'Is Ready', '', 10);
        $this->RegisterVariableBoolean('IsRunning', 'Is Running', '', 20);

        $this->RegisterVariableFloat('MinSoC', 'Min SoC', '', 30);
        $this->RegisterVariableFloat('MaxSoC', 'Max SoC', '', 40);

        $this->RegisterVariableInteger('PowerSetpoint', 'Power Setpoint', '', 50);
        $this->EnableAction('PowerSetpoint');

        $this->RegisterVariableString('Strategy', 'Strategy', '', 60);
        $this->EnableAction('Strategy');

        $this->RegisterVariableString('LastReadResponse', 'Letzte Lese-Antwort', '', 70);
        $this->RegisterVariableString('LastWriteResponse', 'Letzte Steuer-Antwort', '', 80);

        $this->ConnectParent('{F7A0DD2E-7684-95C0-64C2-D2A9DC47577B}');
        $this->RequireParent('{F7A0DD2E-7684-95C0-64C2-D2A9DC47577B}');
    }

    public function ApplyChanges()
    {
        parent::ApplyChanges();

        $this->SetStatus(IS_ACTIVE);
    }

    public function RequestAction($Ident, $Value)
    {
        switch ($Ident) {

            case 'PowerSetpoint':

                $max = $this->ReadPropertyInteger('MaxPowerSetpoint');

                if ($Value > $max) {
                    $Value = $max;
                }

                if ($Value < ($max * -1)) {
                    $Value = $max * -1;
                }

                SetValue($this->GetIDForIdent('PowerSetpoint'), $Value);

                $this->RunBatteryControl();

                break;

            case 'Strategy':

                SetValueString(
                    $this->GetIDForIdent('Strategy'),
                    (string)$Value
                );

                $this->RunBatteryControl();

                break;
        }
    }

    public function RunBatteryControl()
    {
        $reqActionID       = $this->ReadPropertyInteger('ReqActionID');
        $socID             = $this->ReadPropertyInteger('SoCID');
        $powerProductionID = $this->ReadPropertyInteger('PowerProductionID');

        if (!$this->IsValidVariable($reqActionID)) {
            $this->SendDebug(
                'RunBatteryControl',
                'Keine gültige Ausgabe-Variable gewählt',
                0
            );
            return;
        }

        if (!$this->IsValidVariable($socID)) {
            $this->SendDebug(
                'RunBatteryControl',
                'Keine gültige SoC Variable gewählt',
                0
            );
            return;
        }

        $strategy = GetValueString(
            $this->GetIDForIdent('Strategy')
        );

        $setpoint = GetValue(
            $this->GetIDForIdent('PowerSetpoint')
        );

        $soc = GetValue($socID);

        $targetSoC = $this->ReadPropertyInteger('TargetSoC');

        $chargePower = $this->ReadPropertyInteger('ChargePower');

        $dischargePower = $this->ReadPropertyInteger('DischargePower');

        // -------------------------------------------------
        // Strategy activate
        // -------------------------------------------------

        if ($strategy == 'activate') {

            RequestAction(
                $reqActionID,
                $setpoint * -1
            );

            return;
        }

        // -------------------------------------------------
        // Strategy stop
        // -------------------------------------------------

        if ($strategy == 'stop') {

            RequestAction($reqActionID, 0);

            if ($this->IsValidVariable($powerProductionID)) {
                SetValue($powerProductionID, 0);
            }

            return;
        }

        // -------------------------------------------------
        // Ziel erreicht
        // -------------------------------------------------

        if ((int)$soc == $targetSoC) {

            RequestAction($reqActionID, 0);

            return;
        }

        // -------------------------------------------------
        // Laden
        // -------------------------------------------------

        if ($soc < $targetSoC) {

            RequestAction(
                $reqActionID,
                abs($chargePower)
            );

            return;
        }

        // -------------------------------------------------
        // Entladen
        // -------------------------------------------------

        if ($soc > $targetSoC) {

            RequestAction(
                $reqActionID,
                abs($dischargePower) * -1
            );

            return;
        }
    }

    public function BuildReadResponse()
    {
        $socID = $this->ReadPropertyInteger('SoCID');

        $powerProductionID = $this->ReadPropertyInteger(
            'PowerProductionID'
        );

        $data = [

            'power_production' => $this->IsValidVariable(
                $powerProductionID
            )
                ? GetValue($powerProductionID)
                : 0,

            'is_ready' => GetValue(
                $this->GetIDForIdent('IsReady')
            ),

            'is_running' => GetValue(
                $this->GetIDForIdent('IsRunning')
            ),

            'state_of_charge' => $this->IsValidVariable(
                $socID
            )
                ? GetValue($socID)
                : 0,

            'min_soc' => GetValue(
                $this->GetIDForIdent('MinSoC')
            ),

            'max_soc' => GetValue(
                $this->GetIDForIdent('MaxSoC')
            )
        ];

        $json = json_encode(
            $data,
            JSON_PRETTY_PRINT
        );

        SetValueString(
            $this->GetIDForIdent('LastReadResponse'),
            $json
        );

        return $json;
    }

    public function HandleRemoteControlJSON(string $payload)
    {
        if ($payload == '') {
            return;
        }

        $data = json_decode($payload, true);

        if (!is_array($data)) {
            return;
        }

        // -------------------------------------------------
        // Power Setpoint
        // -------------------------------------------------

        if (isset($data['power_setpoint'])) {

            $max = $this->ReadPropertyInteger(
                'MaxPowerSetpoint'
            );

            $val = (int)$data['power_setpoint'];

            if ($val > $max) {
                $val = $max;
            }

            if ($val < ($max * -1)) {
                $val = $max * -1;
            }

            SetValue(
                $this->GetIDForIdent('PowerSetpoint'),
                $val
            );
        }

        // -------------------------------------------------
        // Strategy
        // -------------------------------------------------

        if (isset($data['strategy'])) {

            SetValueString(
                $this->GetIDForIdent('Strategy'),
                (string)$data['strategy']
            );
        }

        // -------------------------------------------------
        // Batterie-Regelung ausführen
        // -------------------------------------------------

        $this->RunBatteryControl();

        // -------------------------------------------------
        // Antwort bauen
        // -------------------------------------------------

        $output = [

            'power_setpoint' => GetValue(
                $this->GetIDForIdent('PowerSetpoint')
            ),

            'strategy' => GetValueString(
                $this->GetIDForIdent('Strategy')
            )
        ];

        $json = json_encode(
            $output,
            JSON_PRETTY_PRINT
        );

        SetValueString(
            $this->GetIDForIdent('LastWriteResponse'),
            $json
        );

        return $json;
    }

    private function IsValidVariable(int $id)
    {
        return (
            $id > 0
            && IPS_ObjectExists($id)
            && IPS_GetObject($id)['ObjectType'] == 2
        );
    }
}
?>
