Skip to content

Commit

Permalink
Add command to set current and phase limit for EVSE via MQTT API (EVe…
Browse files Browse the repository at this point in the history
…rest#1016)

* Add command to set current and phase limit for EVSE via MQTT API

Introduced a new MQTT topic "everest_api/evse_manager/cmd/set_limit_amps_phases"
to set the current and phase limit for the EVSE.

Signed-off-by: Fabian Hartung <[email protected]>

* Update modules/API/README.md

Co-authored-by: Piet Gömpel <[email protected]>
Signed-off-by: FaHaGit <[email protected]>

---------

Signed-off-by: Fabian Hartung <[email protected]>
Signed-off-by: FaHaGit <[email protected]>
Co-authored-by: Piet Gömpel <[email protected]>
  • Loading branch information
FaHaGit and Pietfried authored Feb 18, 2025
1 parent af9ced9 commit dd7c1eb
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 1 deletion.
61 changes: 61 additions & 0 deletions modules/API/API.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,36 @@ types::energy::ExternalLimits get_external_limits(const std::string& data, bool
return external_limits;
}

types::energy::ExternalLimits get_external_limits(int32_t phases, float amps) {
const auto timestamp = Everest::Date::to_rfc3339(date::utc_clock::now());
types::energy::ExternalLimits external_limits;
types::energy::ScheduleReqEntry target_entry;
target_entry.timestamp = timestamp;

types::energy::ScheduleReqEntry zero_entry;
zero_entry.timestamp = timestamp;
zero_entry.limits_to_leaves.total_power_W = 0;

// check if phases are 1 or 3, otherwise throw an exception
const auto is_valid = (phases == 1 || phases == 3);
if (is_valid) {
target_entry.limits_to_leaves.ac_max_phase_count = phases;
target_entry.limits_to_leaves.ac_min_phase_count = phases;
target_entry.limits_to_leaves.ac_max_current_A = std::fabs(amps);
} else {
std::string error_msg = "Invalid phase count " + std::to_string(phases);
throw std::out_of_range(error_msg);
}

if (amps > 0) {
external_limits.schedule_import.emplace(std::vector<types::energy::ScheduleReqEntry>(1, target_entry));
} else {
external_limits.schedule_export.emplace(std::vector<types::energy::ScheduleReqEntry>(1, target_entry));
external_limits.schedule_import.emplace(std::vector<types::energy::ScheduleReqEntry>(1, zero_entry));
}
return external_limits;
}

static void remove_error_from_list(std::vector<module::SessionInfo::Error>& list, const std::string& error_type) {
list.erase(std::remove_if(list.begin(), list.end(),
[error_type](const module::SessionInfo::Error& err) { return err.type == error_type; }),
Expand Down Expand Up @@ -534,6 +564,37 @@ void API::init() {
EVLOG_warning << "Invalid limit: No conversion of given input could be performed.";
}
});

std::string cmd_set_limit_phases = cmd_base + "set_limit_amps_phases";

this->mqtt.subscribe(cmd_set_limit_phases, [&evse_manager_check = this->evse_manager_check,
&evse_energy_sink = evse_energy_sink](const std::string& data) {
int32_t phases;
float amps;
try {
auto arg = json::parse(data);
if (arg.contains("amps") && arg.contains("phases")) {
amps = arg.at("amps");
phases = arg.at("phases");
} else {
EVLOG_error << "Invalid limit: Missing amps or phases.";
return;
}
} catch (const std::exception& e) {
EVLOG_error << "set_limit_amps_phases: Cannot parse argument, command ignored: " << e.what();
return;
}
try {
const auto external_limits = get_external_limits(phases, amps);
evse_manager_check.wait_ready();
evse_energy_sink.call_set_external_limits(external_limits);
} catch (const std::invalid_argument& e) {
EVLOG_warning << "Invalid limit: No conversion of given input could be performed.";
} catch (const std::out_of_range& e) {
EVLOG_warning << "Invalid limit: Out of range "
<< ", error: " << e.what();
}
});
} else {
EVLOG_warning << "No evse energy sink configured for evse_id: " << evse_id
<< ". API module does therefore not allow control of amps or power limits for this EVSE";
Expand Down
20 changes: 19 additions & 1 deletion modules/API/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,26 @@ Command to set a watt limit for this EVSE that will be considered within the Ene

📌 **Note:** You have to configure one evse_energy_sink connection per EVSE within the configuration file in order to use this topic!

### everest_api/evse_manager/cmd/set_limit_amps_phases
Command to set a current (amps) and a phase limit for this EVSE, which will be considered by the energy
management. The payload should be in the following json format:
```json
{
"amps": 8.0,
"phases": 3
}
```
Setting these limits does not automatically imply that they will be set by the EVSE because the
energy management might consider limitations from other sources, too. The "amps" value can be a
positive or negative number. The "phases" value must be either 1 or 3.
Please consider that switching between AC single-phase (1ph) and three-phase (3ph) charging does only
work if 1ph/3ph switching is activated in the EVerest configuration. For more information please look
in the EVerest documentation.

📌 **Note:** You have to configure one evse_energy_sink connection per EVSE within the configuration file in order to use this topic!

### everest_api/evse_manager/cmd/force_unlock
Command to force unlock a connector on the EVSE. They payload should be a positive integer identifying the connector that should be unlocked. If the payload is empty or cannot be converted to an integer connector 1 is assumed.
Command to force unlock a connector on the EVSE. The payload should be a positive integer identifying the connector that should be unlocked. If the payload is empty or cannot be converted to an integer connector 1 is assumed.

### everest_api/evse_manager/cmd/uk_random_delay
Command to control the UK Smart Charging random delay feature. The payload can be the following enum: "enable" and "disable" to enable/disable the feature entirely or "cancel" to cancel an ongoing delay.
Expand Down

0 comments on commit dd7c1eb

Please sign in to comment.