New plugin: EVBox
parent
effe59e9b9
commit
a72f421db5
|
|
@ -219,6 +219,15 @@ Description: nymea integration plugin for ESPuino
|
|||
This package contains the nymea integration plugin for ESPuino devices.
|
||||
|
||||
|
||||
Package: nymea-plugin-evbox
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
Description: nymea integration plugin for EVBox
|
||||
This package contains the nymea integration plugin for EVBox wallboxes
|
||||
implementing the Protocol Max v4.
|
||||
|
||||
|
||||
Package: nymea-plugin-fastcom
|
||||
Architecture: any
|
||||
Depends: ${misc:Depends},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginevbox.so
|
||||
evbox/translations/*qm usr/share/nymea/translations/
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# EVBox
|
||||
|
||||
This integration allows nymea to control EVBox wallboxes supporting the Protocol Max v4.
|
||||
|
||||
## Supported things
|
||||
|
||||
Generally, all EVBox wallboxes supporting the Protocol Max v4 are supported. We've tested it with
|
||||
|
||||
* Elvi
|
||||
|
||||
## Requirements
|
||||
|
||||
The EVBox Protocol Max v4 is based on a RS485 connection. This means, a RS485 port, either onboard or via USB adapter, is required on the nymea system.
|
||||
The wallbox must be configured to not be cloud controlled, in order to accept commands on the RS485 port.
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
|
|
@ -0,0 +1,9 @@
|
|||
include(../plugins.pri)
|
||||
|
||||
QT += network serialport
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginevbox.cpp \
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginevbox.h \
|
||||
|
|
@ -0,0 +1,348 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by
|
||||
* copyright law, and remains the property of nymea GmbH. All rights, including
|
||||
* reproduction, publication, editing and translation, are reserved. The use of
|
||||
* this project is subject to the terms of a license agreement to be concluded
|
||||
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
|
||||
* under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; version 3. This project is distributed in the hope that
|
||||
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this project. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under
|
||||
* contact@nymea.io or see our FAQ/Licensing Information on
|
||||
* https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
|
||||
#include "integrationpluginevbox.h"
|
||||
#include "plugininfo.h"
|
||||
#include "plugintimer.h"
|
||||
|
||||
#include <QSerialPortInfo>
|
||||
#include <QSerialPort>
|
||||
#include <QDataStream>
|
||||
|
||||
#define STX 0x02
|
||||
#define ETX 0x03
|
||||
|
||||
IntegrationPluginEVBox::IntegrationPluginEVBox()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
IntegrationPluginEVBox::~IntegrationPluginEVBox()
|
||||
{
|
||||
}
|
||||
|
||||
void IntegrationPluginEVBox::discoverThings(ThingDiscoveryInfo *info)
|
||||
{
|
||||
// Create the list of available serial interfaces
|
||||
|
||||
foreach(QSerialPortInfo port, QSerialPortInfo::availablePorts()) {
|
||||
|
||||
qCDebug(dcEVBox()) << "Found serial port:" << port.portName();
|
||||
QString description = port.portName() + " " + port.manufacturer() + " " + port.description();
|
||||
ThingDescriptor thingDescriptor(info->thingClassId(), "EVBox Elvi", description);
|
||||
ParamList parameters;
|
||||
foreach (Thing *existingThing, myThings()) {
|
||||
if (existingThing->paramValue(evboxThingSerialPortParamTypeId).toString() == port.portName()) {
|
||||
thingDescriptor.setThingId(existingThing->id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
parameters.append(Param(evboxThingSerialPortParamTypeId, port.portName()));
|
||||
thingDescriptor.setParams(parameters);
|
||||
info->addThingDescriptor(thingDescriptor);
|
||||
}
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
void IntegrationPluginEVBox::setupThing(ThingSetupInfo *info)
|
||||
{
|
||||
Thing *thing = info->thing();
|
||||
QString interface = thing->paramValue(evboxThingSerialPortParamTypeId).toString();
|
||||
QSerialPort *serialPort = new QSerialPort(interface, info->thing());
|
||||
|
||||
serialPort->setBaudRate(QSerialPort::Baud38400);
|
||||
serialPort->setDataBits(QSerialPort::Data8);
|
||||
serialPort->setStopBits(QSerialPort::OneStop);
|
||||
serialPort->setParity(QSerialPort::NoParity);
|
||||
|
||||
connect(serialPort, &QSerialPort::readyRead, thing, [=]() {
|
||||
thing->setStateValue(evboxConnectedStateTypeId, true);
|
||||
QByteArray data = serialPort->readAll();
|
||||
// qCDebug(dcEVBox()) << "Data received from serial port:" << data;
|
||||
m_inputBuffers[thing].append(data);
|
||||
processInputBuffer(thing);
|
||||
});
|
||||
|
||||
connect(serialPort, static_cast<void(QSerialPort::*)(QSerialPort::SerialPortError)>(&QSerialPort::error), thing, [=](){
|
||||
qCWarning(dcEVBox()) << "Serial Port error" << serialPort->error() << serialPort->errorString();
|
||||
if (serialPort->error() != QSerialPort::NoError) {
|
||||
if (serialPort->isOpen()) {
|
||||
serialPort->close();
|
||||
}
|
||||
thing->setStateValue(evboxConnectedStateTypeId, false);
|
||||
QTimer::singleShot(1000, this, [=](){
|
||||
serialPort->open(QSerialPort::ReadWrite);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (!serialPort->open(QSerialPort::ReadWrite)) {
|
||||
qCWarning(dcEVBox()) << "Unable to open serial port";
|
||||
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Unable to open the RS485 port. Please make sure the RS485 adapter is connected properly."));
|
||||
return;
|
||||
}
|
||||
|
||||
m_serialPorts.insert(thing, serialPort);
|
||||
|
||||
m_pendingSetups.insert(thing, info);
|
||||
connect(info, &ThingSetupInfo::finished, this, [=](){
|
||||
m_pendingSetups.remove(thing);
|
||||
});
|
||||
QTimer::singleShot(2000, info, [=](){
|
||||
qCDebug(dcEVBox()) << "Timeout during setup";
|
||||
delete m_serialPorts.take(info->thing());
|
||||
info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("The EVBox is not responding."));
|
||||
});
|
||||
|
||||
|
||||
sendCommand(thing, Command69, 1);
|
||||
}
|
||||
|
||||
void IntegrationPluginEVBox::thingRemoved(Thing *thing)
|
||||
{
|
||||
m_timers.remove(thing);
|
||||
delete m_serialPorts.take(thing);
|
||||
}
|
||||
|
||||
void IntegrationPluginEVBox::executeAction(ThingActionInfo *info)
|
||||
{
|
||||
Thing *thing = info->thing();
|
||||
|
||||
if (info->action().actionTypeId() == evboxPowerActionTypeId) {
|
||||
bool power = info->action().paramValue(evboxPowerActionPowerParamTypeId).toBool();
|
||||
sendCommand(info->thing(), Command69, power ? info->thing()->stateValue(evboxMaxChargingCurrentStateTypeId).toUInt() : 0);
|
||||
} else if (info->action().actionTypeId() == evboxMaxChargingCurrentActionTypeId) {
|
||||
int maxChargingCurrent = info->action().paramValue(evboxMaxChargingCurrentActionMaxChargingCurrentParamTypeId).toInt();
|
||||
sendCommand(info->thing(), Command69, maxChargingCurrent);
|
||||
}
|
||||
|
||||
m_pendingActions[thing].append(info);
|
||||
connect(info, &ThingActionInfo::finished, this, [=](){
|
||||
m_pendingActions[thing].removeAll(info);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
bool IntegrationPluginEVBox::sendCommand(Thing *thing, Command command, quint16 maxChargingCurrent)
|
||||
{
|
||||
QByteArray commandData;
|
||||
|
||||
commandData += "80"; // Dst addr
|
||||
commandData += "A0"; // Sender address
|
||||
commandData += QString::number(command);
|
||||
commandData += QString("%1").arg(maxChargingCurrent * 10, 4, 10, QChar('0'));
|
||||
commandData += QString("%1").arg(maxChargingCurrent * 10, 4, 10, QChar('0'));
|
||||
commandData += QString("%1").arg(maxChargingCurrent * 10, 4, 10, QChar('0'));
|
||||
commandData += "003C"; // Timeout (60 sec)
|
||||
// If we fail to refresh the wallbox after the timeout, it shall turn off, which is what we'll use as default
|
||||
// when we don't know what its set to (as we can't read it).
|
||||
// Hence we do *not* cache the power and maxChargingCurrent states for this one
|
||||
commandData += QString("%1").arg(0, 4, 10, QChar('0'));
|
||||
commandData += QString("%1").arg(0, 4, 10, QChar('0'));
|
||||
commandData += QString("%1").arg(0, 4, 10, QChar('0'));
|
||||
|
||||
commandData += createChecksum(commandData);
|
||||
|
||||
QByteArray data;
|
||||
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||
stream << static_cast<quint8>(STX);
|
||||
stream.writeRawData(commandData.data(), commandData.length());
|
||||
stream << static_cast<quint8>(ETX);
|
||||
|
||||
qCDebug(dcEVBox()) << "Writing data:" << data << "->" << data.toHex();
|
||||
QSerialPort *serialPort = m_serialPorts.value(thing);
|
||||
qint64 count = serialPort->write(data);
|
||||
if (count == data.length()) {
|
||||
m_waitingForResponses[thing] = true;
|
||||
}
|
||||
return count == data.length();
|
||||
}
|
||||
|
||||
QByteArray IntegrationPluginEVBox::createChecksum(const QByteArray &data) const
|
||||
{
|
||||
QDataStream checksumStream(data);
|
||||
quint8 sum = 0;
|
||||
quint8 xOr = 0;
|
||||
while (!checksumStream.atEnd()) {
|
||||
quint8 byte;
|
||||
checksumStream >> byte;
|
||||
sum += byte;
|
||||
xOr ^= byte;
|
||||
}
|
||||
return QString("%1%2").arg(sum,2,16, QChar('0')).arg(xOr,2,16, QChar('0')).toUpper().toLocal8Bit();
|
||||
}
|
||||
|
||||
void IntegrationPluginEVBox::processInputBuffer(Thing *thing)
|
||||
{
|
||||
QByteArray packet;
|
||||
QDataStream inputStream(m_inputBuffers.value(thing));
|
||||
QDataStream outputStream(&packet, QIODevice::WriteOnly);
|
||||
bool startFound = false, endFound = false;
|
||||
|
||||
while (!inputStream.atEnd()) {
|
||||
quint8 byte;
|
||||
inputStream >> byte;
|
||||
if (!startFound) {
|
||||
if (byte == STX) {
|
||||
startFound = true;
|
||||
continue;
|
||||
} else {
|
||||
qCWarning(dcEVBox()) << "Discarding byte not matching start of frame 0x" + QString::number(byte, 16);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (byte == ETX) {
|
||||
endFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
outputStream << byte;
|
||||
}
|
||||
|
||||
if (startFound && endFound) {
|
||||
m_inputBuffers[thing].remove(0, packet.length() + 2);
|
||||
} else {
|
||||
// qCDebug(dcEVBox()) << "Data is incomplete... Waiting for more...";
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.length() < 2) { // In practice it'll be longer, but let's make sure we won't crash checking the checksum on erraneous data
|
||||
qCWarning(dcEVBox()) << "Packet is too short. Discarding packet...";
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcEVBox()) << "Packet received:" << packet;
|
||||
|
||||
QByteArray checksum = createChecksum(packet.left(packet.length() - 4));
|
||||
if (checksum != packet.right(4)) {
|
||||
qCWarning(dcEVBox()) << "Checksum mismatch for incoming packet:" << packet << "Given checksum:" << packet.right(4) << "Expected:" << checksum;
|
||||
return;
|
||||
}
|
||||
|
||||
// We received something valid... Assuming the last command we've sent is OK.
|
||||
// There's no way to properly match a response to a command, so...
|
||||
if (m_pendingSetups.contains(thing)) {
|
||||
qCDebug(dcEVBox()) << "Finishing setup";
|
||||
|
||||
// Can't use a pluginTimer because it may collide with data on the wire, so we're
|
||||
// manually re-starting the timer whenever we receive something.
|
||||
QTimer *timer = new QTimer(thing);
|
||||
m_timers.insert(thing, timer);
|
||||
timer->setInterval(1000);
|
||||
|
||||
connect(timer, &QTimer::timeout, thing, [=](){
|
||||
thing->setStateValue(evboxConnectedStateTypeId, !m_waitingForResponses[thing]);
|
||||
|
||||
if (thing->stateValue(evboxPowerStateTypeId).toBool()) {
|
||||
sendCommand(thing, Command69, thing->stateValue(evboxMaxChargingCurrentStateTypeId).toDouble());
|
||||
} else {
|
||||
sendCommand(thing, Command69, 0);
|
||||
}
|
||||
});
|
||||
|
||||
m_pendingSetups.take(thing)->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
if (!m_pendingActions.value(thing).isEmpty()) {
|
||||
ThingActionInfo *info = m_pendingActions.value(thing).first();
|
||||
if (info->action().actionTypeId() == evboxPowerActionTypeId) {
|
||||
thing->setStateValue(evboxPowerStateTypeId, info->action().paramValue(evboxPowerActionPowerParamTypeId));
|
||||
} else if (info->action().actionTypeId() == evboxMaxChargingCurrentActionTypeId) {
|
||||
thing->setStateValue(evboxMaxChargingCurrentStateTypeId, info->action().paramValue(evboxMaxChargingCurrentActionMaxChargingCurrentParamTypeId));
|
||||
}
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
processDataPacket(thing, packet);
|
||||
}
|
||||
|
||||
void IntegrationPluginEVBox::processDataPacket(Thing *thing, const QByteArray &packet)
|
||||
{
|
||||
|
||||
// The data is a mess of hex and dec values... So do not wonder about the weird from/to hex mess in here...
|
||||
QDataStream stream(QByteArray::fromHex(packet));
|
||||
|
||||
quint8 from, to, commandId, wallboxCount;
|
||||
quint16 minPollInterval, maxChargingCurrent;
|
||||
stream >> from >> to >> commandId >> minPollInterval >> maxChargingCurrent >> wallboxCount;
|
||||
|
||||
commandId = QString::number(commandId, 16).toInt();
|
||||
|
||||
qCDebug(dcEVBox()) << QString("From: %1, To: %2, CMD: %3, MinPollInterval: %4, maxChargingCurrent: %5, Wallbox data count: %6")
|
||||
.arg(from).arg(to).arg(commandId).arg(minPollInterval).arg(maxChargingCurrent).arg(wallboxCount);
|
||||
|
||||
if (commandId != Command69) {
|
||||
qCWarning(dcEVBox()) << "Only command 69 is implemented! Adjust response parsing if sending other commands.";
|
||||
return;
|
||||
}
|
||||
|
||||
m_waitingForResponses[thing] = false;
|
||||
|
||||
// Command 69 would give a list of wallboxes (they can be chained apparently) but we only support a single one for now
|
||||
// for (int i = 0; i < wallboxCount; i++) {
|
||||
|
||||
if (wallboxCount > 0) {
|
||||
quint16 minChargingCurrent, chargingCurrentL1, chargingCurrentL2, chargingCurrentL3, cosinePhiL1, cosinePhiL2, cosinePhiL3, totalEnergyConsumed;
|
||||
stream >> minChargingCurrent >> chargingCurrentL1 >> chargingCurrentL2 >> chargingCurrentL3 >> cosinePhiL1 >> cosinePhiL2 >> cosinePhiL3 >> totalEnergyConsumed;
|
||||
|
||||
qCDebug(dcEVBox()) << QString("Min current: %1, actual current L1: %2, L2: %3, L3: %4, Total energy: %5")
|
||||
.arg(minChargingCurrent).arg(chargingCurrentL1).arg(chargingCurrentL2).arg(chargingCurrentL3).arg(totalEnergyConsumed);
|
||||
|
||||
thing->setStateMinMaxValues(evboxMaxChargingCurrentStateTypeId, minChargingCurrent / 10, maxChargingCurrent / 10);
|
||||
|
||||
double currentPower = (chargingCurrentL1 + chargingCurrentL2 + chargingCurrentL3) * 23;
|
||||
thing->setStateValue(evboxCurrentPowerStateTypeId, currentPower);
|
||||
|
||||
thing->setStateValue(evboxTotalEnergyConsumedStateTypeId, totalEnergyConsumed / 1000.0);
|
||||
|
||||
thing->setStateValue(evboxChargingStateTypeId, currentPower > 0);
|
||||
|
||||
int phaseCount = 0;
|
||||
if (chargingCurrentL1 > 0) {
|
||||
phaseCount++;
|
||||
}
|
||||
if (chargingCurrentL2 > 0) {
|
||||
phaseCount++;
|
||||
}
|
||||
if (chargingCurrentL3 > 0) {
|
||||
phaseCount++;
|
||||
}
|
||||
// If all phases are on 0, we aren't charging and don't know how may phases are used...
|
||||
// so only updating the count if we actually do know that at least one is charging.
|
||||
if (phaseCount > 0) {
|
||||
thing->setStateValue(evboxPhaseCountStateTypeId, phaseCount);
|
||||
}
|
||||
}
|
||||
|
||||
m_timers.value(thing)->start();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
* This project including source code and documentation is protected by
|
||||
* copyright law, and remains the property of nymea GmbH. All rights, including
|
||||
* reproduction, publication, editing and translation, are reserved. The use of
|
||||
* this project is subject to the terms of a license agreement to be concluded
|
||||
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
|
||||
* under https://nymea.io/license
|
||||
*
|
||||
* GNU Lesser General Public License Usage
|
||||
* Alternatively, this project may be redistributed and/or modified under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; version 3. This project is distributed in the hope that
|
||||
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this project. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* For any further details and any questions please contact us under
|
||||
* contact@nymea.io or see our FAQ/Licensing Information on
|
||||
* https://nymea.io/license/faq
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef INTEGRATIONPLUGINEVBOX_H
|
||||
#define INTEGRATIONPLUGINEVBOX_H
|
||||
|
||||
#include "integrations/integrationplugin.h"
|
||||
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
class QSerialPort;
|
||||
|
||||
class IntegrationPluginEVBox: public IntegrationPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginevbox.json")
|
||||
Q_INTERFACES(IntegrationPlugin)
|
||||
|
||||
public:
|
||||
enum Command {
|
||||
Command68 = 68,
|
||||
Command69 = 69
|
||||
};
|
||||
Q_ENUM(Command)
|
||||
|
||||
explicit IntegrationPluginEVBox();
|
||||
~IntegrationPluginEVBox();
|
||||
|
||||
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||
void setupThing(ThingSetupInfo *info) override;
|
||||
void thingRemoved(Thing *thing) override;
|
||||
void executeAction(ThingActionInfo *info) override;
|
||||
|
||||
private:
|
||||
bool sendCommand(Thing *thing, Command command, quint16 maxChargingCurrent);
|
||||
|
||||
QByteArray createChecksum(const QByteArray &data) const;
|
||||
|
||||
void processInputBuffer(Thing *thing);
|
||||
void processDataPacket(Thing *thing, const QByteArray &packet);
|
||||
|
||||
private:
|
||||
QHash<Thing*, QSerialPort*> m_serialPorts;
|
||||
QHash<Thing*, ThingSetupInfo*> m_pendingSetups;
|
||||
QHash<Thing*, QList<ThingActionInfo*>> m_pendingActions;
|
||||
|
||||
QHash<Thing*, QByteArray> m_inputBuffers;
|
||||
|
||||
QHash<Thing*, QTimer*> m_timers;
|
||||
QHash<Thing*, bool> m_waitingForResponses;
|
||||
};
|
||||
|
||||
#endif // INTEGRATIONPLUGINEVBOX_H
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
{
|
||||
"name": "EVBox",
|
||||
"displayName": "EVBox",
|
||||
"id": "3362ac5c-5e2f-43c0-b3fc-70a98773e119",
|
||||
"vendors": [
|
||||
{
|
||||
"name": "evbox",
|
||||
"displayName": "EVBox",
|
||||
"id": "435d8843-887a-4642-b2f5-cd27d18bdb95",
|
||||
"thingClasses": [
|
||||
{
|
||||
"id": "d73a14e3-10af-47bc-9bc7-a5ff6e52f72c",
|
||||
"name": "evbox",
|
||||
"displayName": "Elvi",
|
||||
"createMethods": ["discovery"],
|
||||
"setupMethod": "justadd",
|
||||
"interfaces": [ "evcharger", "connectable" ],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "bce7c412-c19a-4e60-a11f-fe8308408abf",
|
||||
"name":"serialPort",
|
||||
"displayName": "Serial port",
|
||||
"type": "QString"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "5ef06038-9fa9-4d5d-8d9b-0375b8aa343a",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"cached": false
|
||||
},
|
||||
{
|
||||
"id": "e3ed9334-68bf-47eb-bd9a-d9a800529bce",
|
||||
"name": "power",
|
||||
"displayName": "Charging enabled",
|
||||
"displayNameAction": "Enable/disable charging",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"writable": true,
|
||||
"cached": false
|
||||
},
|
||||
{
|
||||
"id": "cc9ae86d-fc86-473f-ae90-d9eb20d7a011",
|
||||
"name": "maxChargingCurrent",
|
||||
"displayName": "Maximum charging current",
|
||||
"displayNameAction": "Set maximum charging current",
|
||||
"type": "uint",
|
||||
"writable": true,
|
||||
"unit": "Ampere",
|
||||
"minValue": "6",
|
||||
"maxValue": "22",
|
||||
"defaultValue": 6,
|
||||
"cached": false
|
||||
},
|
||||
{
|
||||
"id": "8d3c80b7-f1f1-48de-8b7a-f99b9bc688b7",
|
||||
"name": "currentPower",
|
||||
"displayName": "Current power consumption",
|
||||
"type": "double",
|
||||
"unit": "Watt",
|
||||
"defaultValue": 0,
|
||||
"cached": false
|
||||
},
|
||||
{
|
||||
"id": "9fd15d14-c228-4af6-85af-4cb171d6f9f0",
|
||||
"name": "totalEnergyConsumed",
|
||||
"displayName": "Total consumed energy",
|
||||
"type": "double",
|
||||
"unit": "KiloWattHour",
|
||||
"defaultValue": 0
|
||||
},
|
||||
{
|
||||
"id": "6439fdba-dc03-454f-bc33-0f6e2619d2ab",
|
||||
"name": "charging",
|
||||
"displayName": "Charging",
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "1120abe3-1878-4301-a701-014b24fd1e41",
|
||||
"name": "phaseCount",
|
||||
"displayName": "Used phases",
|
||||
"type": "uint",
|
||||
"minValue": 1,
|
||||
"maxValue": 3,
|
||||
"defaultValue": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"title": "EVBox",
|
||||
"tagline": "Integrates EVBox wallboxes with nymea.",
|
||||
"icon": "evbox-logo-blue.png",
|
||||
"stability": "consumer",
|
||||
"offline": true,
|
||||
"technologies": [
|
||||
"serial-port"
|
||||
],
|
||||
"categories": [
|
||||
"energy"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1">
|
||||
<context>
|
||||
<name>EVBox</name>
|
||||
<message>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="40"/>
|
||||
<source>Charging</source>
|
||||
<extracomment>The name of the StateType ({6439fdba-dc03-454f-bc33-0f6e2619d2ab}) of ThingClass evbox</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="43"/>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="46"/>
|
||||
<source>Charging enabled</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: evbox, ActionType: power, ID: {e3ed9334-68bf-47eb-bd9a-d9a800529bce})
|
||||
----------
|
||||
The name of the StateType ({e3ed9334-68bf-47eb-bd9a-d9a800529bce}) of ThingClass evbox</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="49"/>
|
||||
<source>Connected</source>
|
||||
<extracomment>The name of the StateType ({5ef06038-9fa9-4d5d-8d9b-0375b8aa343a}) of ThingClass evbox</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="52"/>
|
||||
<source>Current power consumption</source>
|
||||
<extracomment>The name of the StateType ({8d3c80b7-f1f1-48de-8b7a-f99b9bc688b7}) of ThingClass evbox</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="55"/>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="58"/>
|
||||
<source>EVBox</source>
|
||||
<extracomment>The name of the vendor ({435d8843-887a-4642-b2f5-cd27d18bdb95})
|
||||
----------
|
||||
The name of the plugin EVBox ({3362ac5c-5e2f-43c0-b3fc-70a98773e119})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="61"/>
|
||||
<source>Elvi</source>
|
||||
<extracomment>The name of the ThingClass ({d73a14e3-10af-47bc-9bc7-a5ff6e52f72c})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="64"/>
|
||||
<source>Enable/disable charging</source>
|
||||
<extracomment>The name of the ActionType ({e3ed9334-68bf-47eb-bd9a-d9a800529bce}) of ThingClass evbox</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="67"/>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="70"/>
|
||||
<source>Maximum charging current</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: evbox, ActionType: maxChargingCurrent, ID: {cc9ae86d-fc86-473f-ae90-d9eb20d7a011})
|
||||
----------
|
||||
The name of the StateType ({cc9ae86d-fc86-473f-ae90-d9eb20d7a011}) of ThingClass evbox</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="73"/>
|
||||
<source>Serial port</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: evbox, Type: thing, ID: {bce7c412-c19a-4e60-a11f-fe8308408abf})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="76"/>
|
||||
<source>Set maximum charging current</source>
|
||||
<extracomment>The name of the ActionType ({cc9ae86d-fc86-473f-ae90-d9eb20d7a011}) of ThingClass evbox</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="79"/>
|
||||
<source>Total consumed energy</source>
|
||||
<extracomment>The name of the StateType ({9fd15d14-c228-4af6-85af-4cb171d6f9f0}) of ThingClass evbox</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../../build/nymea-plugins-Desktop-Debug/evbox/plugininfo.h" line="82"/>
|
||||
<source>Used phases</source>
|
||||
<extracomment>The name of the StateType ({1120abe3-1878-4301-a701-014b24fd1e41}) of ThingClass evbox</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>IntegrationPluginEVBox</name>
|
||||
<message>
|
||||
<location filename="../integrationpluginevbox.cpp" line="101"/>
|
||||
<source>Unable to open the RS485 port. Please make sure the RS485 adapter is connected properly.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../integrationpluginevbox.cpp" line="114"/>
|
||||
<source>The EVBox is not responding.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
@ -22,6 +22,7 @@ PLUGIN_DIRS = \
|
|||
elgato \
|
||||
eq-3 \
|
||||
espuino \
|
||||
evbox \
|
||||
fastcom \
|
||||
flowercare \
|
||||
fronius \
|
||||
|
|
|
|||
Loading…
Reference in New Issue