blob: fe51c9da664b6df28806e5454e16c6f02469b2e1 [file] [log] [blame]
/*
*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <EVSEManufacturerImpl.h>
#include <EnergyEvseManager.h>
#include <app/clusters/energy-evse-server/EnergyEvseTestEventTriggerDelegate.h>
using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::EnergyEvse;
CHIP_ERROR EVSEManufacturer::Init()
{
/* Manufacturers should modify this to do any custom initialisation */
/* Register callbacks */
EnergyEvseDelegate * dg = GetEvseManufacturer()->GetDelegate();
if (dg == nullptr)
{
ChipLogError(AppServer, "EVSE Delegate is not initialized");
return CHIP_ERROR_UNINITIALIZED;
}
dg->HwRegisterEvseCallbackHandler(ApplicationCallbackHandler, reinterpret_cast<intptr_t>(this));
/*
* This is an example implementation for manufacturers to consider
*
* For Manufacturer to specify the hardware capability in mA:
* dg->HwSetMaxHardwareCurrentLimit(32000); // 32A
*
* For Manufacturer to specify the CircuitCapacity in mA (e.g. from DIP switches)
* dg->HwSetCircuitCapacity(20000); // 20A
*
*/
/* Once the system is initialised then check to see if the state was restored
* (e.g. after a power outage), and if the Enable timer check needs to be started
*/
dg->ScheduleCheckOnEnabledTimeout();
return CHIP_NO_ERROR;
}
/*
* When the EV is plugged in, and asking for demand change the state
* and set the CableAssembly current limit
*
* EnergyEvseDelegate * dg = GetEvseManufacturer()->GetDelegate();
* if (dg == nullptr)
* {
* ChipLogError(AppServer, "Delegate is not initialized");
* return CHIP_ERROR_UNINITIALIZED;
* }
*
* dg->HwSetState(StateEnum::kPluggedInDemand);
* dg->HwSetCableAssemblyLimit(63000); // 63A = 63000mA
*
*
* If the vehicle ID can be retrieved (e.g. over Powerline)
* dg->HwSetVehicleID(CharSpan::fromCharString("TEST_VEHICLE_123456789"));
*
*
* If the EVSE has an RFID sensor, the RFID value read can cause an event to be sent
* (e.g. can be used to indicate if a user as tried to activate the charging)
*
* uint8_t uid[10] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE };
* dg->HwSetRFID(ByteSpan(uid));
*/
CHIP_ERROR EVSEManufacturer::Shutdown()
{
return CHIP_NO_ERROR;
}
/**
* @brief Main Callback handler - to be implemented by Manufacturer
*
* @param EVSECbInfo describes the type of call back, and a union of structs
* which contain relevant info for the specific callback type
*
* @param arg - optional pointer to some context information (see register function)
*/
void EVSEManufacturer::ApplicationCallbackHandler(const EVSECbInfo * cb, intptr_t arg)
{
EVSEManufacturer * pClass = reinterpret_cast<EVSEManufacturer *>(arg);
switch (cb->type)
{
case EVSECallbackType::StateChanged:
ChipLogProgress(AppServer, "EVSE callback - state changed");
break;
case EVSECallbackType::ChargeCurrentChanged:
ChipLogProgress(AppServer, "EVSE callback - maxChargeCurrent changed to %ld",
static_cast<long>(cb->ChargingCurrent.maximumChargeCurrent));
break;
case EVSECallbackType::EnergyMeterReadingRequested:
ChipLogProgress(AppServer, "EVSE callback - EnergyMeterReadingRequested");
if (cb->EnergyMeterReadingRequest.meterType == ChargingDischargingType::kCharging)
{
*(cb->EnergyMeterReadingRequest.energyMeterValuePtr) = pClass->mLastChargingEnergyMeter;
}
else
{
*(cb->EnergyMeterReadingRequest.energyMeterValuePtr) = pClass->mLastDischargingEnergyMeter;
}
break;
default:
ChipLogError(AppServer, "Unhandled EVSE Callback type %d", static_cast<int>(cb->type));
}
}
struct EVSETestEventSaveData
{
int64_t mOldMaxHardwareCurrentLimit;
int64_t mOldCircuitCapacity;
int64_t mOldUserMaximumChargeCurrent;
int64_t mOldCableAssemblyLimit;
StateEnum mOldHwStateBasic; /* For storing hwState before Basic Func event */
StateEnum mOldHwStatePluggedIn; /* For storing hwState before PluggedIn event */
StateEnum mOldHwStatePluggedInDemand; /* For storing hwState before PluggedInDemand event */
};
static EVSETestEventSaveData sEVSETestEventSaveData;
EnergyEvseDelegate * GetEvseDelegate()
{
EVSEManufacturer * mn = GetEvseManufacturer();
VerifyOrDieWithMsg(mn != nullptr, AppServer, "EVSEManufacturer is null");
EnergyEvseDelegate * dg = mn->GetDelegate();
VerifyOrDieWithMsg(dg != nullptr, AppServer, "EVSE Delegate is null");
return dg;
}
void SetTestEventTrigger_BasicFunctionality()
{
EnergyEvseDelegate * dg = GetEvseDelegate();
sEVSETestEventSaveData.mOldMaxHardwareCurrentLimit = dg->HwGetMaxHardwareCurrentLimit();
sEVSETestEventSaveData.mOldCircuitCapacity = dg->GetCircuitCapacity();
sEVSETestEventSaveData.mOldUserMaximumChargeCurrent = dg->GetUserMaximumChargeCurrent();
sEVSETestEventSaveData.mOldHwStateBasic = dg->HwGetState();
dg->HwSetMaxHardwareCurrentLimit(32000);
dg->HwSetCircuitCapacity(32000);
dg->SetUserMaximumChargeCurrent(32000);
dg->HwSetState(StateEnum::kNotPluggedIn);
}
void SetTestEventTrigger_BasicFunctionalityClear()
{
EnergyEvseDelegate * dg = GetEvseDelegate();
dg->HwSetMaxHardwareCurrentLimit(sEVSETestEventSaveData.mOldMaxHardwareCurrentLimit);
dg->HwSetCircuitCapacity(sEVSETestEventSaveData.mOldCircuitCapacity);
dg->SetUserMaximumChargeCurrent(sEVSETestEventSaveData.mOldUserMaximumChargeCurrent);
dg->HwSetState(sEVSETestEventSaveData.mOldHwStateBasic);
}
void SetTestEventTrigger_EVPluggedIn()
{
EnergyEvseDelegate * dg = GetEvseDelegate();
sEVSETestEventSaveData.mOldCableAssemblyLimit = dg->HwGetCableAssemblyLimit();
sEVSETestEventSaveData.mOldHwStatePluggedIn = dg->HwGetState();
dg->HwSetCableAssemblyLimit(63000);
dg->HwSetState(StateEnum::kPluggedInNoDemand);
}
void SetTestEventTrigger_EVPluggedInClear()
{
EnergyEvseDelegate * dg = GetEvseDelegate();
dg->HwSetCableAssemblyLimit(sEVSETestEventSaveData.mOldCableAssemblyLimit);
dg->HwSetState(sEVSETestEventSaveData.mOldHwStatePluggedIn);
}
void SetTestEventTrigger_EVChargeDemand()
{
EnergyEvseDelegate * dg = GetEvseDelegate();
sEVSETestEventSaveData.mOldHwStatePluggedInDemand = dg->HwGetState();
dg->HwSetState(StateEnum::kPluggedInDemand);
}
void SetTestEventTrigger_EVChargeDemandClear()
{
EnergyEvseDelegate * dg = GetEvseDelegate();
dg->HwSetState(sEVSETestEventSaveData.mOldHwStatePluggedInDemand);
}
void SetTestEventTrigger_EVSEGroundFault()
{
EnergyEvseDelegate * dg = GetEvseDelegate();
dg->HwSetFault(FaultStateEnum::kGroundFault);
}
void SetTestEventTrigger_EVSEOverTemperatureFault()
{
EnergyEvseDelegate * dg = GetEvseDelegate();
dg->HwSetFault(FaultStateEnum::kOverTemperature);
}
void SetTestEventTrigger_EVSEFaultClear()
{
EnergyEvseDelegate * dg = GetEvseDelegate();
dg->HwSetFault(FaultStateEnum::kNoError);
}
void SetTestEventTrigger_EVSEDiagnosticsComplete()
{
EnergyEvseDelegate * dg = GetEvseDelegate();
dg->HwDiagnosticsComplete();
}
bool HandleEnergyEvseTestEventTrigger(uint64_t eventTrigger)
{
EnergyEvseTrigger trigger = static_cast<EnergyEvseTrigger>(eventTrigger);
switch (trigger)
{
case EnergyEvseTrigger::kBasicFunctionality:
ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => Basic Functionality install");
SetTestEventTrigger_BasicFunctionality();
break;
case EnergyEvseTrigger::kBasicFunctionalityClear:
ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => Basic Functionality clear");
SetTestEventTrigger_BasicFunctionalityClear();
break;
case EnergyEvseTrigger::kEVPluggedIn:
ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EV plugged in");
SetTestEventTrigger_EVPluggedIn();
break;
case EnergyEvseTrigger::kEVPluggedInClear:
ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EV unplugged");
SetTestEventTrigger_EVPluggedInClear();
break;
case EnergyEvseTrigger::kEVChargeDemand:
ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EV Charge Demand");
SetTestEventTrigger_EVChargeDemand();
break;
case EnergyEvseTrigger::kEVChargeDemandClear:
ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EV Charge NoDemand");
SetTestEventTrigger_EVChargeDemandClear();
break;
case EnergyEvseTrigger::kEVSEGroundFault:
ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EVSE has a GroundFault fault");
SetTestEventTrigger_EVSEGroundFault();
break;
case EnergyEvseTrigger::kEVSEOverTemperatureFault:
ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EVSE has a OverTemperature fault");
SetTestEventTrigger_EVSEOverTemperatureFault();
break;
case EnergyEvseTrigger::kEVSEFaultClear:
ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EVSE faults have cleared");
SetTestEventTrigger_EVSEFaultClear();
break;
case EnergyEvseTrigger::kEVSEDiagnosticsComplete:
ChipLogProgress(Support, "[EnergyEVSE-Test-Event] => EVSE Diagnostics Completed");
SetTestEventTrigger_EVSEDiagnosticsComplete();
break;
default:
return false;
}
return true;
}