Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1) - OpenOCPP extracted (firmware OCPP 1.6J/2.0.1) - ShapeShifter library installed (pip install -e) - ShapeShifter specification extracted - EVerest extracted TODO updated with progress
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "Bender_isoCHA425HV.hpp"
|
||||
|
||||
namespace module {
|
||||
|
||||
void Bender_isoCHA425HV::init() {
|
||||
invoke_init(*p_main);
|
||||
}
|
||||
|
||||
void Bender_isoCHA425HV::ready() {
|
||||
invoke_ready(*p_main);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BENDER_ISO_CHA425HV_HPP
|
||||
#define BENDER_ISO_CHA425HV_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for provided interface implementations
|
||||
#include <generated/interfaces/isolation_monitor/Implementation.hpp>
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/serial_communication_hub/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class Bender_isoCHA425HV : public Everest::ModuleBase {
|
||||
public:
|
||||
Bender_isoCHA425HV() = delete;
|
||||
Bender_isoCHA425HV(const ModuleInfo& info, std::unique_ptr<isolation_monitorImplBase> p_main,
|
||||
std::unique_ptr<serial_communication_hubIntf> r_serial_comm_hub, Conf& config) :
|
||||
ModuleBase(info), p_main(std::move(p_main)), r_serial_comm_hub(std::move(r_serial_comm_hub)), config(config){};
|
||||
|
||||
const std::unique_ptr<isolation_monitorImplBase> p_main;
|
||||
const std::unique_ptr<serial_communication_hubIntf> r_serial_comm_hub;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // BENDER_ISO_CHA425HV_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"main/isolation_monitorImpl.cpp"
|
||||
)
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,50 @@
|
||||
.. _everest_modules_handwritten_Bender_isoCHA425HV:
|
||||
|
||||
.. ******************
|
||||
.. Bender_isoCHA425HV
|
||||
.. ******************
|
||||
|
||||
IMD driver for Bender isoCHA IMD devices
|
||||
|
||||
Default settings
|
||||
================
|
||||
|
||||
By default the Bender IsoCHA type insulation monitor devices come pre-configured with the following settings:
|
||||
|
||||
* 19200 baud / even parity / 1 stop-bit
|
||||
* bus address: 3
|
||||
|
||||
If you want to change those settings, you need to use the manufacturer's configuration software or change the settings on the device's LCD display and buttons.
|
||||
|
||||
Bus termination
|
||||
----------------
|
||||
|
||||
The Bender IsoCHA devices come with an internal 120 Ohms switchable bus termination resistor on the modbus connection terminals. To use it, put the switch into the upper (on) position.
|
||||
|
||||
Settings overwritten by the driver
|
||||
----------------------------------
|
||||
|
||||
During initialization, this driver overwrites the following settings:
|
||||
|
||||
* set "pre-alarm" resistor R1 (default = 600k) [register 3005 and following]
|
||||
* set "alarm" resistor R2 to slightly lower than R1 (= -10k) [register 3007]
|
||||
* disable low-voltage alarm [register 3008 and following]
|
||||
* disable overvoltage alarm [register 3010 and following]
|
||||
* set mode to "dc" [register 3023 and following]
|
||||
* disable automatic self-tests [register 3021 and following]
|
||||
* disable line voltage test [register 3024]
|
||||
* disable device (only if the configuration option ``threshold_resistance_kohm`` is set to its maximum of 600 [k Ohms]) [register 3026]
|
||||
|
||||
Startup and operation
|
||||
=====================
|
||||
|
||||
To start the device and begin insulation (and voltage) measurements, send a "start" command via the device's MQTT interface. The device will then begin sending its measurement data once a second.
|
||||
|
||||
After the desired measurement has been retrieved, disable the device via an MQTT "stop" command on its interface.
|
||||
|
||||
Devices with firmware version newer than 5.00 support a faster self test mode to reduce CableCheck time. This will automatically be used if supported by firmware.
|
||||
|
||||
Using the internal alarm functions and relays
|
||||
=============================================
|
||||
|
||||
The external alarm relays should be used to ensure shut down of the DC HV voltage independently from the Linux host. Make sure to configure the thresholds correctly.
|
||||
@@ -0,0 +1,442 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "isolation_monitorImpl.hpp"
|
||||
#include "everest/logging.hpp"
|
||||
#include <chrono>
|
||||
#include <fmt/core.h>
|
||||
#include <thread>
|
||||
#include <utils/date.hpp>
|
||||
|
||||
namespace module {
|
||||
namespace main {
|
||||
|
||||
void isolation_monitorImpl::init() {
|
||||
}
|
||||
|
||||
void isolation_monitorImpl::configure_device() {
|
||||
// Query device name and version
|
||||
bool successful = true;
|
||||
int selftest_enable_at_start_value = config.selftest_enable_at_start ? 1 : 0;
|
||||
if (config.disable_device_on_stop and config.selftest_enable_at_start) {
|
||||
EVLOG_warning << "disable_device_on_stop configuration option and "
|
||||
"selftest_enable_at_start are incompatible. Self test at "
|
||||
"start will be disabled.";
|
||||
selftest_enable_at_start_value = 0;
|
||||
}
|
||||
do {
|
||||
successful = true;
|
||||
successful &= send_to_imd(3000, (config.voltage_to_earth_monitoring_alarm_enable ? 1 : 0));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3005, config.r1_prealarm_kohm);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3007, config.r2_alarm_kohm);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3008, (config.undervoltage_alarm_enable ? 1 : 0));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3009, config.undervoltage_alarm_threshold_V);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3010, (config.overvoltage_alarm_enable ? 1 : 0));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3011, config.overvoltage_alarm_threshold_V);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3012, (config.alarm_memory_enable ? 1 : 0));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3013, (config.relais_r1_mode ? 1 : 0));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3014, (config.relais_r2_mode ? 1 : 0));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3018, (config.delay_startup_device ? 1 : 0));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3019, config.delay_t_on_k1_k2);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3020, config.delay_t_off_k1_k2);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3023, (config.chademo_mode ? 1 : 0));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3024, (config.selftest_enable_gridconnection ? 1 : 0));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3025, selftest_enable_at_start_value);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3027, config.relay_k1_alarm_assignment);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
successful &= send_to_imd(3028, config.relay_k2_alarm_assignment);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
// start up enable the device if the configuration option is not set
|
||||
if (!config.disable_device_on_stop) {
|
||||
successful &= send_to_imd(3026, 1);
|
||||
}
|
||||
// Give device time to process startup command
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
if (successful) {
|
||||
EVLOG_info << "IMD Device: " << read_device_name() << " (" << read_firmware_version() << ")";
|
||||
faster_cable_check_supported = check_for_faster_cablecheck();
|
||||
|
||||
if (faster_cable_check_supported) {
|
||||
EVLOG_info << "Supports faster cable check method";
|
||||
enable_faster_cable_check_mode();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
} else {
|
||||
EVLOG_info << "Does not support faster cable check method, falling "
|
||||
"back to long self test. This may create "
|
||||
"timeouts with certain cars in CableCheck. Consider "
|
||||
"upgrading to at least firmware 5.00";
|
||||
disable_faster_cable_check_mode();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
} else {
|
||||
// allow the system to recover and don't hog the MODBUS
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
}
|
||||
} while (not successful);
|
||||
}
|
||||
|
||||
void isolation_monitorImpl::start_self_test() {
|
||||
if (last_test != TestType::ExternalTest) {
|
||||
// Wait a bit to ensure device is ready (not processing previous read
|
||||
// operations) This prevents conflicts with the regular reading loop
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
if (mod->r_serial_comm_hub->call_modbus_write_multiple_registers(
|
||||
config.imd_device_id, static_cast<int>(8005),
|
||||
(types::serial_comm_hub_requests::VectorUint16){{0x5445}}) !=
|
||||
types::serial_comm_hub_requests::StatusCodeEnum::Success) {
|
||||
set_deviceFault("Failed to start self test");
|
||||
self_test_started = false;
|
||||
return;
|
||||
}
|
||||
// Give device time to process the self-test command
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
self_test_started = true;
|
||||
self_test_timeout = 30;
|
||||
}
|
||||
|
||||
void isolation_monitorImpl::set_deviceFault(const std::string& message) {
|
||||
if (!error_state_monitor->is_error_active("isolation_monitor/DeviceFault", "")) {
|
||||
auto error =
|
||||
error_factory->create_error("isolation_monitor/DeviceFault", "", message, Everest::error::Severity::High);
|
||||
raise_error(error);
|
||||
}
|
||||
}
|
||||
|
||||
void isolation_monitorImpl::clear_deviceFault() {
|
||||
if (error_state_monitor->is_error_active("isolation_monitor/DeviceFault", "")) {
|
||||
clear_error("isolation_monitor/DeviceFault");
|
||||
}
|
||||
}
|
||||
|
||||
bool isolation_monitorImpl::enable_faster_cable_check_mode() {
|
||||
return send_to_imd(3021, 3);
|
||||
}
|
||||
|
||||
bool isolation_monitorImpl::disable_faster_cable_check_mode() {
|
||||
return send_to_imd(3021, 0);
|
||||
}
|
||||
|
||||
bool isolation_monitorImpl::send_to_imd(const uint16_t& command, const uint16_t& value) {
|
||||
if (mod->r_serial_comm_hub->call_modbus_write_multiple_registers(
|
||||
config.imd_device_id, static_cast<int>(command),
|
||||
(types::serial_comm_hub_requests::VectorUint16){{value}}) !=
|
||||
types::serial_comm_hub_requests::StatusCodeEnum::Success) {
|
||||
EVLOG_error << "ModBus Command failed: " << command << " Value: " << value;
|
||||
set_deviceFault("Failed to write registers");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void isolation_monitorImpl::ready() {
|
||||
this->configure_device();
|
||||
bool self_test_running = false;
|
||||
bool need_to_disable_device = false;
|
||||
int device_disabled_timeout_s = 10;
|
||||
|
||||
while (true) {
|
||||
read_imd_values();
|
||||
|
||||
if (self_test_started) {
|
||||
self_test_timeout--;
|
||||
if (self_test_timeout <= 0) {
|
||||
// a time out happend
|
||||
self_test_started = false;
|
||||
need_to_disable_device = true;
|
||||
// publish failed result
|
||||
EVLOG_warning << "Self test timed out";
|
||||
publish_self_test_result(false);
|
||||
}
|
||||
if (self_test_running) {
|
||||
if (last_test not_eq TestType::ExternalTest) {
|
||||
// Self test is done
|
||||
self_test_running = false;
|
||||
self_test_started = false;
|
||||
need_to_disable_device = true;
|
||||
// was it successfull? If there is no error, it was...
|
||||
bool result = true;
|
||||
if (last_alarm == AlarmType::DeviceError) {
|
||||
result = false;
|
||||
}
|
||||
EVLOG_info << "Self test completed: " << result;
|
||||
publish_self_test_result(result);
|
||||
}
|
||||
} else {
|
||||
if (last_test == TestType::ExternalTest) {
|
||||
self_test_running = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (not error_state_monitor->is_error_active("isolation_monitor/DeviceFault", "")) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
if (need_to_disable_device) {
|
||||
device_disabled_timeout_s--;
|
||||
if (device_disabled_timeout_s <= 0) {
|
||||
need_to_disable_device = false;
|
||||
device_disabled_timeout_s = 10;
|
||||
// disable the device if the configuration option is set and we are not publishing
|
||||
// aka we are in a measuring cycle (start called)
|
||||
if (not enable_publishing && config.disable_device_on_stop) {
|
||||
if (not send_to_imd(3026, 0)) {
|
||||
EVLOG_error << "Can't disable the device: " << read_device_name();
|
||||
} else {
|
||||
EVLOG_info << "Device disabled after self test since we didn't start measuring cycle "
|
||||
"(timeout 10s)";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void isolation_monitorImpl::handle_start() {
|
||||
enable_publishing = true;
|
||||
if (config.disable_device_on_stop) {
|
||||
if (not send_to_imd(3026, 1)) {
|
||||
EVLOG_error << "Can't enable the device: " << read_device_name();
|
||||
} else {
|
||||
EVLOG_info << "Device enabled for measurements";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void isolation_monitorImpl::handle_stop() {
|
||||
enable_publishing = false;
|
||||
if (config.disable_device_on_stop) {
|
||||
if (not send_to_imd(3026, 0)) {
|
||||
EVLOG_error << "Can't disable the device: " << read_device_name();
|
||||
} else {
|
||||
EVLOG_info << "Device disabled after measurements";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void isolation_monitorImpl::handle_start_self_test(double& test_voltage_V) {
|
||||
EVLOG_info << "IMD Starting self-test...";
|
||||
// make sure that the device is on
|
||||
if (config.disable_device_on_stop) {
|
||||
if (not send_to_imd(3026, 1)) {
|
||||
EVLOG_error << "Can't enable the device: " << read_device_name();
|
||||
} else {
|
||||
EVLOG_info << "Device enabled for self test";
|
||||
}
|
||||
}
|
||||
start_self_test();
|
||||
}
|
||||
|
||||
void isolation_monitorImpl::read_imd_values() {
|
||||
// Read rF
|
||||
auto rf = read_register(ImdRegisters::RESISTANCE_R_F_OHM);
|
||||
EVLOG_debug << "Resistance: " << to_string(rf);
|
||||
|
||||
last_test = rf.test;
|
||||
last_alarm = rf.alarm;
|
||||
|
||||
// Small delay between reads to avoid overwhelming the device
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
// Read Voltage U_N (always needed)
|
||||
auto voltage = read_register(ImdRegisters::VOLTAGE_U_N_V);
|
||||
EVLOG_debug << "Voltage: " << to_string(voltage);
|
||||
|
||||
isolation_monitorImpl::MeasurementValue voltage_to_earth_l1e;
|
||||
isolation_monitorImpl::MeasurementValue voltage_to_earth_l2e;
|
||||
// Read Voltage to Earth L1E and L2E only if the device is not in self test
|
||||
// mode and only it we are in a measuring cycle. We have seen that Bender
|
||||
// sometimes is overwhelmed
|
||||
if ((last_test == TestType::NoTest) and (enable_publishing or config.always_publish_measurements)) {
|
||||
// VOLTAGE_U_L1E_V (1016) and VOLTAGE_U_L2E_V (1020) are consecutive (4
|
||||
// registers apart) Read 8 registers starting from 1016 to get both
|
||||
// measurements in a single operation
|
||||
types::serial_comm_hub_requests::Result register_response =
|
||||
mod->r_serial_comm_hub->call_modbus_read_holding_registers(
|
||||
config.imd_device_id, static_cast<int>(ImdRegisters::VOLTAGE_U_L1E_V), 8);
|
||||
|
||||
if (register_response.status_code == types::serial_comm_hub_requests::StatusCodeEnum::Success and
|
||||
register_response.value.has_value() and register_response.value.value().size() == 8) {
|
||||
const auto& reg_value_int = register_response.value.value();
|
||||
// Convert std::vector<int> to std::vector<uint16_t>
|
||||
std::vector<uint16_t> reg_value(reg_value_int.begin(), reg_value_int.end());
|
||||
|
||||
// Parse voltage U_L1E from registers 0-3
|
||||
voltage_to_earth_l1e = parse_register_data(reg_value, 0);
|
||||
EVLOG_debug << "Voltage to Earth L1E: " << to_string(voltage_to_earth_l1e);
|
||||
|
||||
// Parse voltage U_L2E from registers 4-7
|
||||
voltage_to_earth_l2e = parse_register_data(reg_value, 4);
|
||||
EVLOG_debug << "Voltage to Earth L2E: " << to_string(voltage_to_earth_l2e);
|
||||
} else {
|
||||
// Fallback to individual reads
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
voltage_to_earth_l1e = read_register(ImdRegisters::VOLTAGE_U_L1E_V);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
voltage_to_earth_l2e = read_register(ImdRegisters::VOLTAGE_U_L2E_V);
|
||||
}
|
||||
}
|
||||
|
||||
if (last_alarm == AlarmType::DeviceError) {
|
||||
set_deviceFault("Device Error");
|
||||
}
|
||||
|
||||
bool valid_readings = true;
|
||||
if (enable_publishing or config.always_publish_measurements) {
|
||||
types::isolation_monitor::IsolationMeasurement m;
|
||||
if (voltage.valid not_eq ValidType::Invalid) {
|
||||
m.voltage_V = voltage.value;
|
||||
} else {
|
||||
valid_readings = false;
|
||||
}
|
||||
|
||||
if (voltage_to_earth_l1e.valid not_eq ValidType::Invalid) {
|
||||
m.voltage_to_earth_l1e_V = voltage_to_earth_l1e.value;
|
||||
} else {
|
||||
valid_readings = false;
|
||||
}
|
||||
|
||||
if (voltage_to_earth_l2e.valid not_eq ValidType::Invalid) {
|
||||
m.voltage_to_earth_l2e_V = voltage_to_earth_l2e.value;
|
||||
} else {
|
||||
valid_readings = false;
|
||||
}
|
||||
|
||||
if (rf.valid not_eq ValidType::Invalid) {
|
||||
m.resistance_F_Ohm = rf.value;
|
||||
} else {
|
||||
valid_readings = false;
|
||||
}
|
||||
|
||||
// do not publish values if in error state or the device is in self test
|
||||
// mode
|
||||
if (last_test == TestType::NoTest) {
|
||||
if (not error_state_monitor->is_error_active("isolation_monitor/DeviceFault", "")) {
|
||||
publish_isolation_measurement(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
// let at least one round of values unpublished not to use unstable ones
|
||||
if (last_alarm not_eq AlarmType::DeviceError and valid_readings and
|
||||
error_state_monitor->is_error_active("isolation_monitor/DeviceFault", "")) {
|
||||
clear_deviceFault();
|
||||
configure_device();
|
||||
}
|
||||
}
|
||||
|
||||
std::string isolation_monitorImpl::read_device_name() {
|
||||
auto result = mod->r_serial_comm_hub->call_modbus_read_holding_registers(
|
||||
config.imd_device_id, static_cast<std::underlying_type_t<ImdRegisters>>(ImdRegisters::DEVICE_NAME), 10);
|
||||
std::string device_name;
|
||||
if (result.status_code == types::serial_comm_hub_requests::StatusCodeEnum::Success) {
|
||||
for (int character : result.value.value()) {
|
||||
device_name.push_back(static_cast<char>(character >> 8));
|
||||
device_name.push_back(static_cast<char>(character & 0xFF));
|
||||
}
|
||||
} else {
|
||||
set_deviceFault("Can't read device name");
|
||||
}
|
||||
|
||||
// Strip and new lines that may be present in device name
|
||||
std::replace(device_name.begin(), device_name.end(), '\n', ' ');
|
||||
return device_name;
|
||||
}
|
||||
|
||||
std::string isolation_monitorImpl::read_firmware_version() {
|
||||
auto result = mod->r_serial_comm_hub->call_modbus_read_holding_registers(
|
||||
config.imd_device_id, static_cast<std::underlying_type_t<ImdRegisters>>(ImdRegisters::DEVICE_FIRMWARE_VERSION),
|
||||
6);
|
||||
std::string firmware_version;
|
||||
if (result.status_code == types::serial_comm_hub_requests::StatusCodeEnum::Success) {
|
||||
firmware_version = fmt::format("Ident: {} | Version {}, Date: {}-{}-{} | Modbus Driver: {}",
|
||||
result.value.value()[0], result.value.value()[1], result.value.value()[2],
|
||||
result.value.value()[3], result.value.value()[4], result.value.value()[5]);
|
||||
} else {
|
||||
set_deviceFault("Can't read the firmware version");
|
||||
}
|
||||
return firmware_version;
|
||||
}
|
||||
|
||||
bool isolation_monitorImpl::check_for_faster_cablecheck() {
|
||||
auto result = mod->r_serial_comm_hub->call_modbus_read_holding_registers(
|
||||
config.imd_device_id,
|
||||
static_cast<std::underlying_type_t<ImdRegisters>>(ImdRegisters::DEVICE_FIRMWARE_VERSION) + 1, 1);
|
||||
std::string firmware_version;
|
||||
if (result.status_code == types::serial_comm_hub_requests::StatusCodeEnum::Success) {
|
||||
if (result.value.value()[0] > 500) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
set_deviceFault("Could not check if the device supports fast cable check");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isolation_monitorImpl::MeasurementValue isolation_monitorImpl::read_register(const ImdRegisters start_register) {
|
||||
types::serial_comm_hub_requests::Result register_response{};
|
||||
|
||||
register_response = mod->r_serial_comm_hub->call_modbus_read_holding_registers(
|
||||
config.imd_device_id, static_cast<std::underlying_type<ImdRegisters>::type>(start_register), 4);
|
||||
|
||||
MeasurementValue m;
|
||||
|
||||
if (register_response.status_code != types::serial_comm_hub_requests::StatusCodeEnum::Success) {
|
||||
set_deviceFault("Can't read registers");
|
||||
}
|
||||
|
||||
if (not register_response.value.has_value() or register_response.value.value().size() not_eq 4) {
|
||||
// force an error since we did not received fully the registers
|
||||
m.alarm = AlarmType::DeviceError;
|
||||
return m;
|
||||
}
|
||||
|
||||
// Convert std::vector<int> to std::vector<uint16_t>
|
||||
const auto& reg_value_int = register_response.value.value();
|
||||
std::vector<uint16_t> reg_value(reg_value_int.begin(), reg_value_int.end());
|
||||
return parse_register_data(reg_value, 0);
|
||||
}
|
||||
|
||||
isolation_monitorImpl::MeasurementValue
|
||||
isolation_monitorImpl::parse_register_data(const std::vector<uint16_t>& reg_value, size_t offset) {
|
||||
MeasurementValue m;
|
||||
|
||||
if (reg_value.size() < offset + 4) {
|
||||
m.alarm = AlarmType::DeviceError;
|
||||
return m;
|
||||
}
|
||||
|
||||
m.alarm = to_alarm_type(reg_value.at(offset + 2) >> 8);
|
||||
m.test = to_test_type(reg_value.at(offset + 2) >> 8);
|
||||
m.unit = to_unit_type(reg_value.at(offset + 2) & 0xFF);
|
||||
m.valid = to_valid_type(reg_value.at(offset + 2) & 0xFF);
|
||||
m.description = to_channel_description(reg_value.at(offset + 3));
|
||||
|
||||
uint32_t value{0};
|
||||
value += reg_value.at(offset + 0) << 16;
|
||||
value += reg_value.at(offset + 1);
|
||||
auto val = *reinterpret_cast<float*>(&value);
|
||||
m.value = val;
|
||||
return m;
|
||||
}
|
||||
|
||||
} // namespace main
|
||||
} // namespace module
|
||||
@@ -0,0 +1,425 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef MAIN_ISOLATION_MONITOR_IMPL_HPP
|
||||
#define MAIN_ISOLATION_MONITOR_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/isolation_monitor/Implementation.hpp>
|
||||
|
||||
#include "../Bender_isoCHA425HV.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace main {
|
||||
|
||||
struct Conf {
|
||||
int imd_device_id;
|
||||
int r1_prealarm_kohm;
|
||||
int r2_alarm_kohm;
|
||||
bool undervoltage_alarm_enable;
|
||||
int undervoltage_alarm_threshold_V;
|
||||
bool overvoltage_alarm_enable;
|
||||
int overvoltage_alarm_threshold_V;
|
||||
bool alarm_memory_enable;
|
||||
bool relais_r1_mode;
|
||||
bool relais_r2_mode;
|
||||
int delay_startup_device;
|
||||
int delay_t_on_k1_k2;
|
||||
int delay_t_off_k1_k2;
|
||||
bool chademo_mode;
|
||||
bool selftest_enable_gridconnection;
|
||||
bool selftest_enable_at_start;
|
||||
int relay_k1_alarm_assignment;
|
||||
int relay_k2_alarm_assignment;
|
||||
bool always_publish_measurements;
|
||||
bool voltage_to_earth_monitoring_alarm_enable;
|
||||
bool disable_device_on_stop;
|
||||
};
|
||||
|
||||
class isolation_monitorImpl : public isolation_monitorImplBase {
|
||||
public:
|
||||
isolation_monitorImpl() = delete;
|
||||
isolation_monitorImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<Bender_isoCHA425HV>& mod,
|
||||
Conf& config) :
|
||||
isolation_monitorImplBase(ev, "main"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
// insert your public definitions here
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// command handler functions (virtual)
|
||||
virtual void handle_start() override;
|
||||
virtual void handle_stop() override;
|
||||
virtual void handle_start_self_test(double& test_voltage_V) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<Bender_isoCHA425HV>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
enum class ImdRegisters : uint16_t {
|
||||
RESISTANCE_R_F_OHM = 1000,
|
||||
VOLTAGE_U_N_V = 1008,
|
||||
VOLTAGE_U_L1E_V = 1016,
|
||||
VOLTAGE_U_L2E_V = 1020,
|
||||
RESISTANCE_R_FU_OHM = 1028,
|
||||
DEVICE_NAME = 9800,
|
||||
DEVICE_FIRMWARE_VERSION = 9820,
|
||||
};
|
||||
|
||||
enum class AlarmType {
|
||||
NoAlarm,
|
||||
PreWarning,
|
||||
DeviceError,
|
||||
Warning,
|
||||
Alarm,
|
||||
Reserved,
|
||||
};
|
||||
|
||||
std::string to_string(AlarmType a) {
|
||||
switch (a) {
|
||||
case AlarmType::NoAlarm:
|
||||
return "NoAlarm";
|
||||
case AlarmType::PreWarning:
|
||||
return "PreWarning";
|
||||
case AlarmType::DeviceError:
|
||||
return "DeviceError";
|
||||
case AlarmType::Warning:
|
||||
return "Warning";
|
||||
case AlarmType::Alarm:
|
||||
return "Alarm";
|
||||
case AlarmType::Reserved:
|
||||
return "Reserved";
|
||||
}
|
||||
return "Reserved";
|
||||
};
|
||||
|
||||
enum class TestType {
|
||||
NoTest,
|
||||
InternalTest,
|
||||
ExternalTest,
|
||||
};
|
||||
|
||||
std::string to_string(TestType a) {
|
||||
switch (a) {
|
||||
case TestType::NoTest:
|
||||
return "NoTest";
|
||||
case TestType::InternalTest:
|
||||
return "InternalTest";
|
||||
case TestType::ExternalTest:
|
||||
return "ExternalTest";
|
||||
}
|
||||
return "NoTest";
|
||||
};
|
||||
|
||||
enum class ValidType {
|
||||
TrueValue,
|
||||
TrueValueIsSmaller,
|
||||
TrueValueIsBigger,
|
||||
Invalid,
|
||||
};
|
||||
|
||||
std::string to_string(ValidType a) {
|
||||
switch (a) {
|
||||
case ValidType::TrueValue:
|
||||
return "TrueValue";
|
||||
case ValidType::TrueValueIsSmaller:
|
||||
return "TrueValueIsSmaller";
|
||||
case ValidType::TrueValueIsBigger:
|
||||
return "TrueValueIsBigger";
|
||||
case ValidType::Invalid:
|
||||
return "Invalid";
|
||||
}
|
||||
return "Invalid";
|
||||
};
|
||||
|
||||
enum class UnitType {
|
||||
Invalid,
|
||||
NoUnit,
|
||||
Ohm,
|
||||
Ampere,
|
||||
Volt,
|
||||
Percent,
|
||||
Hertz,
|
||||
Baud,
|
||||
Farad,
|
||||
Henry,
|
||||
DegC,
|
||||
DegF,
|
||||
Seconds,
|
||||
Minutes,
|
||||
Hours,
|
||||
Days,
|
||||
Months,
|
||||
};
|
||||
|
||||
std::string to_string(UnitType a) {
|
||||
switch (a) {
|
||||
case UnitType::Invalid:
|
||||
return "Invalid";
|
||||
case UnitType::NoUnit:
|
||||
return "NoUnit";
|
||||
case UnitType::Ohm:
|
||||
return "Ohm";
|
||||
case UnitType::Ampere:
|
||||
return "Ampere";
|
||||
case UnitType::Volt:
|
||||
return "Volt";
|
||||
case UnitType::Percent:
|
||||
return "Percent";
|
||||
case UnitType::Hertz:
|
||||
return "Hertz";
|
||||
case UnitType::Baud:
|
||||
return "Baud";
|
||||
case UnitType::Farad:
|
||||
return "Farad";
|
||||
case UnitType::Henry:
|
||||
return "Henry";
|
||||
case UnitType::DegC:
|
||||
return "DegC";
|
||||
case UnitType::DegF:
|
||||
return "DegF";
|
||||
case UnitType::Seconds:
|
||||
return "Seconds";
|
||||
case UnitType::Minutes:
|
||||
return "Minutes";
|
||||
case UnitType::Hours:
|
||||
return "Hours";
|
||||
case UnitType::Days:
|
||||
return "Days";
|
||||
case UnitType::Months:
|
||||
return "Months";
|
||||
}
|
||||
return "Invalid";
|
||||
};
|
||||
|
||||
enum class ChannelDescription {
|
||||
Undefined,
|
||||
IsolationError,
|
||||
IsolationError_rF,
|
||||
Voltage,
|
||||
UnderVoltage,
|
||||
OverVoltage,
|
||||
Capacity,
|
||||
IsolationError_Zi,
|
||||
GridConnection,
|
||||
EarthConnection,
|
||||
DeviceErrorIsometer,
|
||||
DeviceError,
|
||||
OwnAddress,
|
||||
};
|
||||
|
||||
std::string to_string(ChannelDescription a) {
|
||||
switch (a) {
|
||||
case ChannelDescription::Undefined:
|
||||
return "Undefined";
|
||||
case ChannelDescription::IsolationError:
|
||||
return "IsolationError";
|
||||
case ChannelDescription::IsolationError_rF:
|
||||
return "IsolationError_rF";
|
||||
case ChannelDescription::Voltage:
|
||||
return "Voltage";
|
||||
case ChannelDescription::UnderVoltage:
|
||||
return "UnderVoltage";
|
||||
case ChannelDescription::OverVoltage:
|
||||
return "OverVoltage";
|
||||
case ChannelDescription::Capacity:
|
||||
return "Capacity";
|
||||
case ChannelDescription::IsolationError_Zi:
|
||||
return "IsolationError_Zi";
|
||||
case ChannelDescription::GridConnection:
|
||||
return "GridConnection";
|
||||
case ChannelDescription::EarthConnection:
|
||||
return "EarthConnection";
|
||||
case ChannelDescription::DeviceErrorIsometer:
|
||||
return "DeviceErrorIsometer";
|
||||
case ChannelDescription::DeviceError:
|
||||
return "DeviceError";
|
||||
case ChannelDescription::OwnAddress:
|
||||
return "OwnAddress";
|
||||
}
|
||||
return "Undefined";
|
||||
};
|
||||
|
||||
ChannelDescription to_channel_description(uint16_t raw) {
|
||||
switch (raw) {
|
||||
case 1:
|
||||
return ChannelDescription::IsolationError;
|
||||
case 71:
|
||||
return ChannelDescription::IsolationError_rF;
|
||||
case 76:
|
||||
return ChannelDescription::Voltage;
|
||||
case 77:
|
||||
return ChannelDescription::UnderVoltage;
|
||||
case 78:
|
||||
return ChannelDescription::OverVoltage;
|
||||
case 82:
|
||||
return ChannelDescription::Capacity;
|
||||
case 86:
|
||||
return ChannelDescription::IsolationError_Zi;
|
||||
case 101:
|
||||
return ChannelDescription::GridConnection;
|
||||
case 102:
|
||||
return ChannelDescription::EarthConnection;
|
||||
case 115:
|
||||
return ChannelDescription::DeviceErrorIsometer;
|
||||
case 129:
|
||||
return ChannelDescription::DeviceError;
|
||||
case 145:
|
||||
return ChannelDescription::OwnAddress;
|
||||
default:
|
||||
return ChannelDescription::Undefined;
|
||||
}
|
||||
};
|
||||
|
||||
UnitType to_unit_type(uint8_t raw) {
|
||||
uint8_t t = raw & 0x1F;
|
||||
switch (t) {
|
||||
case 0:
|
||||
return UnitType::Invalid;
|
||||
case 1:
|
||||
return UnitType::NoUnit;
|
||||
case 2:
|
||||
return UnitType::Ohm;
|
||||
case 3:
|
||||
return UnitType::Ampere;
|
||||
case 4:
|
||||
return UnitType::Volt;
|
||||
case 5:
|
||||
return UnitType::Percent;
|
||||
case 6:
|
||||
return UnitType::Hertz;
|
||||
case 7:
|
||||
return UnitType::Baud;
|
||||
case 8:
|
||||
return UnitType::Farad;
|
||||
case 9:
|
||||
return UnitType::Henry;
|
||||
case 10:
|
||||
return UnitType::DegC;
|
||||
case 11:
|
||||
return UnitType::DegF;
|
||||
case 12:
|
||||
return UnitType::Seconds;
|
||||
case 13:
|
||||
return UnitType::Minutes;
|
||||
case 14:
|
||||
return UnitType::Hours;
|
||||
case 15:
|
||||
return UnitType::Days;
|
||||
case 16:
|
||||
return UnitType::Months;
|
||||
}
|
||||
return UnitType::Invalid;
|
||||
};
|
||||
|
||||
ValidType to_valid_type(uint8_t raw) {
|
||||
uint8_t t = raw >> 6;
|
||||
if (t == 1) {
|
||||
return ValidType::TrueValueIsSmaller;
|
||||
} else if (t == 2) {
|
||||
return ValidType::TrueValueIsBigger;
|
||||
} else if (t == 3) {
|
||||
return ValidType::Invalid;
|
||||
} else {
|
||||
return ValidType::TrueValue;
|
||||
}
|
||||
};
|
||||
|
||||
TestType to_test_type(uint8_t raw) {
|
||||
uint8_t t = raw >> 6;
|
||||
if (t == 1) {
|
||||
return TestType::InternalTest;
|
||||
} else if (t == 2) {
|
||||
return TestType::ExternalTest;
|
||||
} else {
|
||||
return TestType::NoTest;
|
||||
}
|
||||
};
|
||||
|
||||
AlarmType to_alarm_type(uint8_t raw) {
|
||||
uint8_t t = raw & 0x07;
|
||||
|
||||
if (t == 0x00) {
|
||||
return AlarmType::NoAlarm;
|
||||
} else if (t == 0x01) {
|
||||
return AlarmType::PreWarning;
|
||||
} else if (t == 0x02 and (raw & 0xC0) == 0x00) {
|
||||
return AlarmType::DeviceError;
|
||||
} else if (t == 0x04) {
|
||||
return AlarmType::Warning;
|
||||
} else if (t == 0x05) {
|
||||
return AlarmType::Alarm;
|
||||
} else {
|
||||
return AlarmType::Reserved;
|
||||
}
|
||||
};
|
||||
|
||||
struct MeasurementValue {
|
||||
float value{0.};
|
||||
AlarmType alarm{AlarmType::NoAlarm};
|
||||
TestType test{TestType::NoTest};
|
||||
UnitType unit{UnitType::Invalid};
|
||||
ValidType valid{ValidType::Invalid};
|
||||
ChannelDescription description{ChannelDescription::Undefined};
|
||||
};
|
||||
|
||||
MeasurementValue read_register(const ImdRegisters start_register);
|
||||
MeasurementValue parse_register_data(const std::vector<uint16_t>& reg_value, size_t offset);
|
||||
|
||||
std::string to_string(MeasurementValue m) {
|
||||
return fmt::format(" {} [{}] [{}] [{}] [{}] [{}]", m.value, to_string(m.unit), to_string(m.valid),
|
||||
to_string(m.description), to_string(m.alarm), to_string(m.test));
|
||||
};
|
||||
|
||||
types::isolation_monitor::IsolationMeasurement isolation_measurement_data{};
|
||||
|
||||
std::thread output_thread;
|
||||
std::atomic_bool enable_publishing{false};
|
||||
std::atomic_bool self_test_started{false};
|
||||
std::atomic_int self_test_timeout{0};
|
||||
|
||||
TestType last_test{TestType::NoTest};
|
||||
AlarmType last_alarm{AlarmType::NoAlarm};
|
||||
|
||||
void set_deviceFault(const std::string& message);
|
||||
void clear_deviceFault();
|
||||
|
||||
void configure_device();
|
||||
void start_measurements();
|
||||
void stop_measurements();
|
||||
void start_self_test();
|
||||
bool send_to_imd(const uint16_t& command, const uint16_t& value);
|
||||
void read_imd_values();
|
||||
std::string read_device_name();
|
||||
std::string read_firmware_version();
|
||||
bool check_for_faster_cablecheck();
|
||||
bool enable_faster_cable_check_mode();
|
||||
bool disable_faster_cable_check_mode();
|
||||
bool faster_cable_check_supported{false};
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
};
|
||||
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
// insert other definitions here
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
|
||||
} // namespace main
|
||||
} // namespace module
|
||||
|
||||
#endif // MAIN_ISOLATION_MONITOR_IMPL_HPP
|
||||
@@ -0,0 +1,139 @@
|
||||
description: IMD driver for Bender isoCHA425HV IMD devices.
|
||||
provides:
|
||||
main:
|
||||
description: Implementation of the driver functionality
|
||||
interface: isolation_monitor
|
||||
config:
|
||||
imd_device_id:
|
||||
description: The IMD's address on the ModBus
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 255
|
||||
default: 3
|
||||
r1_prealarm_kohm:
|
||||
description: >-
|
||||
3005 The IMD's internal measurement resistance for signaling an alarm in kiloohms
|
||||
(the internal resistance is only used for switching the IMDs relays,
|
||||
EVerest handles any isolation issue internaly inside the EVSE manager)
|
||||
Note the maximum value is 600k on isoCHA and 500k on isoEV units.
|
||||
type: integer
|
||||
minimum: 15
|
||||
maximum: 600
|
||||
default: 250
|
||||
r2_alarm_kohm:
|
||||
description: >-
|
||||
3007 This value must be smaller than r1_prealarm_kohm
|
||||
type: integer
|
||||
minimum: 15
|
||||
maximum: 600
|
||||
default: 100
|
||||
undervoltage_alarm_enable:
|
||||
description: >-
|
||||
3008 Enable under voltage alarm
|
||||
type: boolean
|
||||
default: false
|
||||
undervoltage_alarm_threshold_V:
|
||||
description: >-
|
||||
3009 Threshold in volt for the under voltage alarm
|
||||
type: integer
|
||||
default: 30
|
||||
overvoltage_alarm_enable:
|
||||
description: >-
|
||||
3010 Enable over voltage alarm
|
||||
type: boolean
|
||||
default: false
|
||||
overvoltage_alarm_threshold_V:
|
||||
description: >-
|
||||
3011 Threshold in volt for the over voltage alarm
|
||||
type: integer
|
||||
default: 1050
|
||||
alarm_memory_enable:
|
||||
description: >-
|
||||
3012 Enable memory for alarm events
|
||||
type: boolean
|
||||
default: false
|
||||
relais_r1_mode:
|
||||
description: >-
|
||||
3013 false: normally open, true: normally closed
|
||||
type: boolean
|
||||
default: false
|
||||
relais_r2_mode:
|
||||
description: >-
|
||||
3014 false: normally open, true: normally closed
|
||||
type: boolean
|
||||
default: false
|
||||
delay_startup_device:
|
||||
description: >-
|
||||
3018 Delay when device is starting up
|
||||
type: integer
|
||||
maximum: 10
|
||||
minimum: 0
|
||||
default: 5
|
||||
delay_t_on_k1_k2:
|
||||
description: >-
|
||||
3019 delay for switching relais on
|
||||
type: integer
|
||||
maximum: 99
|
||||
minimum: 0
|
||||
default: 5
|
||||
delay_t_off_k1_k2:
|
||||
description: >-
|
||||
3020 delay for switching relais off
|
||||
type: integer
|
||||
maximum: 99
|
||||
minimum: 0
|
||||
default: 5
|
||||
chademo_mode:
|
||||
description: >-
|
||||
3023: false: CCS, true: ChaDeMo
|
||||
type: boolean
|
||||
default: false
|
||||
selftest_enable_gridconnection:
|
||||
description: >-
|
||||
3024: Test grid connection while testing device nEt
|
||||
type: boolean
|
||||
default: false
|
||||
selftest_enable_at_start:
|
||||
description: >-
|
||||
3025 Perform self test at start up of device
|
||||
type: boolean
|
||||
default: true
|
||||
relay_k1_alarm_assignment:
|
||||
description: >-
|
||||
3027 Alarm assignment of relay K1 "r1". Bitmask: S.AL(11) Ue>(10) Ce>(9) test(8) U>(7) U<(6) -R2<(5) +R2<(4) -R1<(3) +R1<(2) Err(1)
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 65535
|
||||
default: 0
|
||||
relay_k2_alarm_assignment:
|
||||
description: >-
|
||||
3028 Alarm assignment of relay K2 "r2". Bitmask: S.AL(11) Ue>(10) Ce>(9) test(8) U>(7) U<(6) -R2<(5) +R2<(4) -R1<(3) +R1<(2) Err(1)
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 65535
|
||||
default: 0
|
||||
always_publish_measurements:
|
||||
description: >-
|
||||
Always publish measurement even if stopped by EVerest
|
||||
type: boolean
|
||||
default: false
|
||||
voltage_to_earth_monitoring_alarm_enable:
|
||||
description: >-
|
||||
3000 Enable over voltage to earth monitoring alarm
|
||||
type: boolean
|
||||
default: false
|
||||
disable_device_on_stop:
|
||||
description: >-
|
||||
Disable the device upon stop measurement
|
||||
type: boolean
|
||||
default: false
|
||||
requires:
|
||||
serial_comm_hub:
|
||||
interface: serial_communication_hub
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Cornelius Claussen
|
||||
- Florin Mihut
|
||||
- Jan Christoph Habig
|
||||
- Lars Dieckmann
|
||||
Reference in New Issue
Block a user