diff --git a/evbox/README.md b/evbox/README.md
index fed95b89..1ece872d 100644
--- a/evbox/README.md
+++ b/evbox/README.md
@@ -7,6 +7,7 @@ This integration allows nymea to control EVBox wallboxes supporting the Protocol
Generally, all EVBox wallboxes supporting the Protocol Max v4 are supported. We've tested it with
* Elvi
+* Elvi + MID meter
## Requirements
diff --git a/evbox/integrationpluginevbox.cpp b/evbox/integrationpluginevbox.cpp
index 9dba178f..f3de66fc 100644
--- a/evbox/integrationpluginevbox.cpp
+++ b/evbox/integrationpluginevbox.cpp
@@ -83,10 +83,12 @@ void IntegrationPluginEVBox::discoverThings(ThingDiscoveryInfo *info)
return;
}
- ThingDescriptor thingDescriptor(info->thingClassId(), "EVBox Elvi", serial);
+ ThingDescriptor thingDescriptor(info->thingClassId(), thingClass(info->thingClassId()).displayName(), serial);
+ ParamTypeId serialPortParamTypeId = thingClass(info->thingClassId()).paramTypes().findByName("serialPort").id();
+ ParamTypeId serialNumberParamTypeId = thingClass(info->thingClassId()).paramTypes().findByName("serialNumber").id();
ParamList params{
- {evboxThingSerialPortParamTypeId, portInfo.portName()},
- {evboxThingSerialNumberParamTypeId, serial}
+ {serialPortParamTypeId, portInfo.portName()},
+ {serialNumberParamTypeId, serial}
};
thingDescriptor.setParams(params);
Thing *existingThing = myThings().findByParams(params);
@@ -117,8 +119,8 @@ void IntegrationPluginEVBox::discoverThings(ThingDiscoveryInfo *info)
void IntegrationPluginEVBox::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
- QString portName = thing->paramValue(evboxThingSerialPortParamTypeId).toString();
- QString serialNumber = thing->paramValue(evboxThingSerialNumberParamTypeId).toString();
+ QString portName = thing->paramValue("serialPort").toString();
+ QString serialNumber = thing->paramValue("serialNumber").toString();
// Opening the port, sharing with others if already opened.
EVBoxPort *port = m_ports.value(portName);
@@ -154,7 +156,7 @@ void IntegrationPluginEVBox::setupThing(ThingSetupInfo *info)
// And connect the signals to the thing for when the setup went well
connect(port, &EVBoxPort::closed, thing, [thing, portName](){
qCInfo(dcEVBox()) << "Port" << portName << "closed. Marking thing as offline:" << thing->name();
- thing->setStateValue(evboxConnectedStateTypeId, false);
+ thing->setStateValue("connected", false);
});
connect(port, &EVBoxPort::opened, thing, [portName](){
qCInfo(dcEVBox()) << "Port" << portName << "opened.";
@@ -164,7 +166,7 @@ void IntegrationPluginEVBox::setupThing(ThingSetupInfo *info)
if (serial != serialNumber) {
return;
}
- thing->setStateValue(evboxConnectedStateTypeId, true);
+ thing->setStateValue("connected", true);
finishPendingAction(thing);
m_waitingForResponses[thing] = false;
});
@@ -173,31 +175,37 @@ void IntegrationPluginEVBox::setupThing(ThingSetupInfo *info)
if (serial != serialNumber) {
return;
}
- thing->setStateValue(evboxConnectedStateTypeId, true);
+ thing->setStateValue("connected", true);
finishPendingAction(thing);
m_waitingForResponses[thing] = false;
- double currentPower = (chargingCurrentL1 + chargingCurrentL2 + chargingCurrentL3) * 23;
- thing->setStateValue(evboxCurrentPowerStateTypeId, currentPower);
- thing->setStateMinMaxValues(evboxMaxChargingCurrentStateTypeId, minChargingCurrent / 10, maxChargingCurrent / 10);
- thing->setStateValue(evboxTotalEnergyConsumedStateTypeId, totalEnergyConsumed / 1000.0);
- thing->setStateValue(evboxChargingStateTypeId, currentPower > 0);
+ thing->setStateMinMaxValues("maxChargingCurrent", minChargingCurrent / 10, maxChargingCurrent / 10);
- 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 many phases are available...
- // Only updating the count if we actually do know that at least one is charging.
- if (phaseCount > 0) {
- thing->setStateValue(evboxPhaseCountStateTypeId, phaseCount);
+ if (thing->thingClassId() == elviMidThingClassId) {
+ double currentPower = (chargingCurrentL1 + chargingCurrentL2 + chargingCurrentL3) * 23;
+ thing->setStateValue("currentPower", currentPower);
+ thing->setStateValue("totalEnergyConsumed", totalEnergyConsumed / 1000.0);
+ thing->setStateValue("charging", 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 many phases are available...
+ // Only updating the count if we actually do know that at least one is charging.
+ if (phaseCount > 0) {
+ thing->setStateValue("phaseCount", phaseCount);
+ }
+ } else {
+ thing->setStateValue("charging", thing->stateValue("maxChargingCurrent").toUInt() > 0 && thing->stateValue("power").toBool());
+ thing->setStateValue("phaseCount", thing->setting("phaseCount").toUInt());
}
+
});
}
@@ -207,19 +215,19 @@ void IntegrationPluginEVBox::postSetupThing(Thing */*thing*/)
m_timer = hardwareManager()->pluginTimerManager()->registerTimer(5);
connect(m_timer, &PluginTimer::timeout, this, [this](){
foreach (Thing *t, myThings()) {
- QString portName = t->paramValue(evboxThingSerialPortParamTypeId).toString();
- QString serial = t->paramValue(evboxThingSerialNumberParamTypeId).toString();
+ QString portName = t->paramValue("serialPort").toString();
+ QString serial = t->paramValue("serialNumber").toString();
if (m_waitingForResponses.value(t)) {
qCInfo(dcEVBox()) << "Wallbox" << t->name() << "did not respond to last command. Marking offline.";
- t->setStateValue(evboxConnectedStateTypeId, false);
+ t->setStateValue("connected", false);
}
EVBoxPort *port = m_ports.value(portName);
if (port->isOpen()) {
quint16 maxChargingCurrent = 0;
- if (t->stateValue(evboxPowerStateTypeId).toBool()) {
- maxChargingCurrent = t->stateValue(evboxMaxChargingCurrentStateTypeId).toUInt();
+ if (t->stateValue("power").toBool()) {
+ maxChargingCurrent = t->stateValue("maxChargingCurrent").toUInt();
}
port->sendCommand(EVBoxPort::Command68, 60, maxChargingCurrent, serial);
m_waitingForResponses[t] = true;
@@ -231,8 +239,9 @@ void IntegrationPluginEVBox::postSetupThing(Thing */*thing*/)
void IntegrationPluginEVBox::thingRemoved(Thing *thing)
{
- QString portName = thing->paramValue(evboxThingSerialPortParamTypeId).toString();
- if (myThings().filterByParam(evboxThingSerialPortParamTypeId, portName).isEmpty()) {
+ QString portName = thing->paramValue("serialPort").toString();
+ ParamTypeId serialPortParamTypeId = thing->thingClass().paramTypes().findByName("serialPort").id();
+ if (myThings().filterByParam(serialPortParamTypeId, portName).isEmpty()) {
qCInfo(dcEVBox()).nospace() << "No more EVBox devices using port " << portName << ". Destroying port.";
delete m_ports.take(portName);
}
@@ -247,17 +256,18 @@ void IntegrationPluginEVBox::executeAction(ThingActionInfo *info)
{
Thing *thing = info->thing();
- QString portName = thing->paramValue(evboxThingSerialPortParamTypeId).toString();
- QString serial = thing->paramValue(evboxThingSerialNumberParamTypeId).toString();
+ QString portName = thing->paramValue("serialPort").toString();
+ QString serial = thing->paramValue("serialNumber").toString();
EVBoxPort *port = m_ports.value(portName);
qCDebug(dcEVBox()) << "Executing action" << info->action().actionTypeId().toString();
- if (info->action().actionTypeId() == evboxPowerActionTypeId) {
- bool power = info->action().paramValue(evboxPowerActionPowerParamTypeId).toBool();
- quint16 maxChargingCurrent = thing->stateValue(evboxMaxChargingCurrentStateTypeId).toUInt();
+ ActionType actionType = thing->thingClass().actionTypes().findById(info->action().actionTypeId());
+ if (actionType.name() == "power") {
+ bool power = info->action().paramValue(actionType.id()).toBool();
+ quint16 maxChargingCurrent = thing->stateValue("maxChargingCurrent").toUInt();
port->sendCommand(EVBoxPort::Command68, 60, power ? maxChargingCurrent : 0, serial);
- } else if (info->action().actionTypeId() == evboxMaxChargingCurrentActionTypeId) {
- int maxChargingCurrent = info->action().paramValue(evboxMaxChargingCurrentActionMaxChargingCurrentParamTypeId).toInt();
+ } else if (actionType.name() == "maxChargingCurrent") {
+ int maxChargingCurrent = info->action().paramValue(actionType.id()).toInt();
port->sendCommand(EVBoxPort::Command68, 60, maxChargingCurrent, serial);
}
@@ -273,10 +283,11 @@ void IntegrationPluginEVBox::finishPendingAction(Thing *thing)
if (!m_pendingActions.value(thing).isEmpty()) {
ThingActionInfo *info = m_pendingActions.value(thing).first();
qCDebug(dcEVBox()) << "Finishing action:" << info->action().actionTypeId().toString();
- 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));
+ ActionType actionType = thing->thingClass().actionTypes().findById(info->action().actionTypeId());
+ if (actionType.name() == "power") {
+ thing->setStateValue("power", info->action().paramValue(actionType.id()));
+ } else if (actionType.name() == "maxChargingCurrent") {
+ thing->setStateValue("maxChargingCurrent", info->action().paramValue(actionType.id()));
}
info->finish(Thing::ThingErrorNoError);
}
diff --git a/evbox/integrationpluginevbox.json b/evbox/integrationpluginevbox.json
index 8952e7b2..b596f4ca 100644
--- a/evbox/integrationpluginevbox.json
+++ b/evbox/integrationpluginevbox.json
@@ -10,11 +10,12 @@
"thingClasses": [
{
"id": "d73a14e3-10af-47bc-9bc7-a5ff6e52f72c",
- "name": "evbox",
- "displayName": "Elvi",
+ "name": "elviMid",
+ "displayName": "Elvi + MID meter",
"createMethods": ["discovery"],
+ "discoveryType": "weak",
"setupMethod": "justadd",
- "interfaces": [ "evcharger", "connectable" ],
+ "interfaces": [ "evcharger", "smartmeterconsumer", "connectable" ],
"paramTypes": [
{
"id": "bce7c412-c19a-4e60-a11f-fe8308408abf",
@@ -94,6 +95,88 @@
"defaultValue": 1
}
]
+ },
+ {
+ "id": "81df1344-3861-4554-972c-6cd4b2ec97a7",
+ "name": "elvi",
+ "displayName": "Elvi",
+ "createMethods": ["discovery"],
+ "discoveryType": "weak",
+ "setupMethod": "justadd",
+ "interfaces": [ "evcharger", "connectable" ],
+ "paramTypes": [
+ {
+ "id": "159fec55-e73d-4a9d-bbde-b2b44fe7f363",
+ "name":"serialPort",
+ "displayName": "Serial port",
+ "type": "QString"
+ },
+ {
+ "id": "987ddd33-cbcd-4716-bdaa-6824a5295d22",
+ "name":"serialNumber",
+ "displayName": "Serial number",
+ "type": "QString"
+ }
+ ],
+ "settingsTypes": [
+ {
+ "id": "3b44ed38-5cfe-4f61-8ad4-a4fe282944ac",
+ "name": "phaseCount",
+ "displayName": "Connected phases",
+ "type": "uint",
+ "minValue": 1,
+ "maxValue": 3,
+ "defaultValue": 3
+ }
+ ],
+ "stateTypes": [
+ {
+ "id": "e763b450-e180-4afb-9fcf-c75ad2f3d7c7",
+ "name": "connected",
+ "displayName": "Connected",
+ "displayNameEvent": "Connected changed",
+ "type": "bool",
+ "defaultValue": false,
+ "cached": false
+ },
+ {
+ "id": "d9875cbf-3736-484c-bf07-08a1d7f9cc89",
+ "name": "power",
+ "displayName": "Charging enabled",
+ "displayNameAction": "Enable/disable charging",
+ "type": "bool",
+ "defaultValue": false,
+ "writable": true
+ },
+ {
+ "id": "186d792a-5bab-4144-837a-cbf5027de4fb",
+ "name": "maxChargingCurrent",
+ "displayName": "Maximum charging current",
+ "displayNameAction": "Set maximum charging current",
+ "type": "uint",
+ "writable": true,
+ "unit": "Ampere",
+ "minValue": "6",
+ "maxValue": "32",
+ "defaultValue": 6
+ },
+ {
+ "id": "91093627-ddae-4ba2-83f1-0241ea01aa01",
+ "name": "charging",
+ "displayName": "Charging",
+ "type": "bool",
+ "defaultValue": false
+ },
+ {
+ "id": "46781438-2a31-48d3-a140-11593888b268",
+ "name": "phaseCount",
+ "displayName": "Used phases",
+ "type": "uint",
+ "minValue": 1,
+ "maxValue": 3,
+ "defaultValue": 1
+ }
+ ]
}
]
}
diff --git a/evbox/translations/3362ac5c-5e2f-43c0-b3fc-70a98773e119-en_US.ts b/evbox/translations/3362ac5c-5e2f-43c0-b3fc-70a98773e119-en_US.ts
index 0d41216c..aaf338ab 100644
--- a/evbox/translations/3362ac5c-5e2f-43c0-b3fc-70a98773e119-en_US.ts
+++ b/evbox/translations/3362ac5c-5e2f-43c0-b3fc-70a98773e119-en_US.ts
@@ -4,35 +4,53 @@
EVBox
-
+
+
Charging
- The name of the StateType ({6439fdba-dc03-454f-bc33-0f6e2619d2ab}) of ThingClass evbox
-
-
-
-
-
- Charging enabled
- The name of the ParamType (ThingClass: evbox, ActionType: power, ID: {e3ed9334-68bf-47eb-bd9a-d9a800529bce})
+ The name of the StateType ({91093627-ddae-4ba2-83f1-0241ea01aa01}) of ThingClass elvi
----------
-The name of the StateType ({e3ed9334-68bf-47eb-bd9a-d9a800529bce}) of ThingClass evbox
+The name of the StateType ({6439fdba-dc03-454f-bc33-0f6e2619d2ab}) of ThingClass elviMid
-
+
+
+
+
+ Charging enabled
+ The name of the ParamType (ThingClass: elvi, ActionType: power, ID: {d9875cbf-3736-484c-bf07-08a1d7f9cc89})
+----------
+The name of the StateType ({d9875cbf-3736-484c-bf07-08a1d7f9cc89}) of ThingClass elvi
+----------
+The name of the ParamType (ThingClass: elviMid, ActionType: power, ID: {e3ed9334-68bf-47eb-bd9a-d9a800529bce})
+----------
+The name of the StateType ({e3ed9334-68bf-47eb-bd9a-d9a800529bce}) of ThingClass elviMid
+
+
+
+
+
Connected
- The name of the StateType ({5ef06038-9fa9-4d5d-8d9b-0375b8aa343a}) of ThingClass evbox
+ The name of the StateType ({e763b450-e180-4afb-9fcf-c75ad2f3d7c7}) of ThingClass elvi
+----------
+The name of the StateType ({5ef06038-9fa9-4d5d-8d9b-0375b8aa343a}) of ThingClass elviMid
-
+
+ Connected phases
+ The name of the ParamType (ThingClass: elvi, Type: settings, ID: {3b44ed38-5cfe-4f61-8ad4-a4fe282944ac})
+
+
+
+
Current power consumption
- The name of the StateType ({8d3c80b7-f1f1-48de-8b7a-f99b9bc688b7}) of ThingClass evbox
+ The name of the StateType ({8d3c80b7-f1f1-48de-8b7a-f99b9bc688b7}) of ThingClass elviMid
-
-
+
+
EVBox
The name of the vendor ({435d8843-887a-4642-b2f5-cd27d18bdb95})
----------
@@ -40,60 +58,104 @@ The name of the plugin EVBox ({3362ac5c-5e2f-43c0-b3fc-70a98773e119})
-
+
Elvi
+ The name of the ThingClass ({81df1344-3861-4554-972c-6cd4b2ec97a7})
+
+
+
+
+ Elvi + MID meter
The name of the ThingClass ({d73a14e3-10af-47bc-9bc7-a5ff6e52f72c})
-
+
+
Enable/disable charging
- The name of the ActionType ({e3ed9334-68bf-47eb-bd9a-d9a800529bce}) of ThingClass evbox
-
-
-
-
-
- Maximum charging current
- The name of the ParamType (ThingClass: evbox, ActionType: maxChargingCurrent, ID: {cc9ae86d-fc86-473f-ae90-d9eb20d7a011})
+ The name of the ActionType ({d9875cbf-3736-484c-bf07-08a1d7f9cc89}) of ThingClass elvi
----------
-The name of the StateType ({cc9ae86d-fc86-473f-ae90-d9eb20d7a011}) of ThingClass evbox
+The name of the ActionType ({e3ed9334-68bf-47eb-bd9a-d9a800529bce}) of ThingClass elviMid
-
+
+
+
+
+ Maximum charging current
+ The name of the ParamType (ThingClass: elvi, ActionType: maxChargingCurrent, ID: {186d792a-5bab-4144-837a-cbf5027de4fb})
+----------
+The name of the StateType ({186d792a-5bab-4144-837a-cbf5027de4fb}) of ThingClass elvi
+----------
+The name of the ParamType (ThingClass: elviMid, ActionType: maxChargingCurrent, ID: {cc9ae86d-fc86-473f-ae90-d9eb20d7a011})
+----------
+The name of the StateType ({cc9ae86d-fc86-473f-ae90-d9eb20d7a011}) of ThingClass elviMid
+
+
+
+
+
+ Serial number
+ The name of the ParamType (ThingClass: elvi, Type: thing, ID: {987ddd33-cbcd-4716-bdaa-6824a5295d22})
+----------
+The name of the ParamType (ThingClass: elviMid, Type: thing, ID: {abc607a7-7dc5-48d4-b3d0-1545ddc63592})
+
+
+
+
+
Serial port
- The name of the ParamType (ThingClass: evbox, Type: thing, ID: {bce7c412-c19a-4e60-a11f-fe8308408abf})
+ The name of the ParamType (ThingClass: elvi, Type: thing, ID: {159fec55-e73d-4a9d-bbde-b2b44fe7f363})
+----------
+The name of the ParamType (ThingClass: elviMid, Type: thing, ID: {bce7c412-c19a-4e60-a11f-fe8308408abf})
-
+
+
Set maximum charging current
- The name of the ActionType ({cc9ae86d-fc86-473f-ae90-d9eb20d7a011}) of ThingClass evbox
+ The name of the ActionType ({186d792a-5bab-4144-837a-cbf5027de4fb}) of ThingClass elvi
+----------
+The name of the ActionType ({cc9ae86d-fc86-473f-ae90-d9eb20d7a011}) of ThingClass elviMid
-
+
Total consumed energy
- The name of the StateType ({9fd15d14-c228-4af6-85af-4cb171d6f9f0}) of ThingClass evbox
+ The name of the StateType ({9fd15d14-c228-4af6-85af-4cb171d6f9f0}) of ThingClass elviMid
-
+
+
Used phases
- The name of the StateType ({1120abe3-1878-4301-a701-014b24fd1e41}) of ThingClass evbox
+ The name of the StateType ({46781438-2a31-48d3-a140-11593888b268}) of ThingClass elvi
+----------
+The name of the StateType ({1120abe3-1878-4301-a701-014b24fd1e41}) of ThingClass elviMid
IntegrationPluginEVBox
-
+
+ No serial ports are available on this system. Please connect a RS485 adapter first.
+
+
+
+
+ Unable to open the RS485 port. Please make sure the RS485 adapter is connected properly and not in use by anything else.
+
+
+
+
Unable to open the RS485 port. Please make sure the RS485 adapter is connected properly.
-
+
+
The EVBox is not responding.