Merge PR #295: Generic things: Add extended smart meter
This commit is contained in:
commit
b474201f62
@ -40,15 +40,10 @@ IntegrationPluginGenericThings::IntegrationPluginGenericThings()
|
||||
|
||||
}
|
||||
|
||||
void IntegrationPluginGenericThings::init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IntegrationPluginGenericThings::setupThing(ThingSetupInfo *info)
|
||||
{
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
Thing *thing = info->thing();
|
||||
|
||||
if (thing->thingClassId() == extendedBlindThingClassId) {
|
||||
uint closingTime = thing->setting(extendedBlindSettingsClosingTimeParamTypeId).toUInt();
|
||||
if (closingTime == 0) {
|
||||
@ -189,7 +184,28 @@ void IntegrationPluginGenericThings::setupThing(ThingSetupInfo *info)
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (thing->thingClassId() == extendedSmartMeterConsumerThingClassId) {
|
||||
|
||||
QTimer* smartMeterTimer = new QTimer(this);
|
||||
int timeframe = thing->setting(extendedSmartMeterConsumerSettingsImpulseTimeframeParamTypeId).toInt();
|
||||
smartMeterTimer->setInterval(timeframe * 1000);
|
||||
m_smartMeterTimer.insert(thing, smartMeterTimer);
|
||||
smartMeterTimer->start();
|
||||
connect(thing, &Thing::settingChanged, smartMeterTimer, [smartMeterTimer] (const ParamTypeId ¶mTypeId, const QVariant &value) {
|
||||
if (paramTypeId == extendedSmartMeterConsumerSettingsImpulseTimeframeParamTypeId) {
|
||||
smartMeterTimer->setInterval(value.toInt() * 1000);
|
||||
}
|
||||
});
|
||||
|
||||
connect(smartMeterTimer, &QTimer::timeout, thing, [this, smartMeterTimer, thing] {
|
||||
double impulsePerKwh = thing->setting(extendedSmartMeterConsumerSettingsImpulsePerKwhParamTypeId).toDouble();
|
||||
int interval = smartMeterTimer->interval()/1000;
|
||||
double power = (m_pulsesPerTimeframe.value(thing)/impulsePerKwh)/(interval/3600.00); // Power = Energy/Time; Energy = Impulses/ImpPerkWh
|
||||
thing->setStateValue(extendedSmartMeterConsumerCurrentPowerStateTypeId, power*1000);
|
||||
m_pulsesPerTimeframe.insert(thing, 0);
|
||||
});
|
||||
}
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
void IntegrationPluginGenericThings::executeAction(ThingActionInfo *info)
|
||||
@ -475,6 +491,21 @@ void IntegrationPluginGenericThings::executeAction(ThingActionInfo *info)
|
||||
} else {
|
||||
Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8());
|
||||
}
|
||||
} else if (thing->thingClassId() == extendedSmartMeterConsumerThingClassId) {
|
||||
if (action.actionTypeId() == extendedSmartMeterConsumerImpulseInputActionTypeId) {
|
||||
bool value = info->action().param(extendedSmartMeterConsumerImpulseInputActionImpulseInputParamTypeId).value().toBool();
|
||||
thing->setStateValue(extendedSmartMeterConsumerImpulseInputStateTypeId, value);
|
||||
int impulsePerKwh = info->thing()->setting(extendedSmartMeterConsumerSettingsImpulsePerKwhParamTypeId).toInt();
|
||||
if (value) {
|
||||
double currentEnergy = thing->stateValue(extendedSmartMeterConsumerTotalEnergyConsumedStateTypeId).toDouble();
|
||||
thing->setStateValue(extendedSmartMeterConsumerTotalEnergyConsumedStateTypeId ,currentEnergy + (1.00/impulsePerKwh));
|
||||
m_pulsesPerTimeframe[thing]++;
|
||||
}
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
return;
|
||||
} else {
|
||||
Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8());
|
||||
}
|
||||
} else {
|
||||
Q_ASSERT_X(false, "executeAction", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
|
||||
}
|
||||
@ -490,6 +521,11 @@ void IntegrationPluginGenericThings::thingRemoved(Thing *thing)
|
||||
m_extendedBlindTargetPercentage.remove(thing);
|
||||
m_venetianBlindAngleTimer.take(thing)->deleteLater();
|
||||
m_venetianBlindTargetAngle.remove(thing);
|
||||
} else if (thing->thingClassId() == extendedSmartMeterConsumerThingClassId) {
|
||||
m_pulsesPerTimeframe.remove(thing);
|
||||
} else if (thing->thingClassId() == extendedSmartMeterConsumerThingClassId) {
|
||||
m_smartMeterTimer.take(thing)->deleteLater();
|
||||
m_pulsesPerTimeframe.remove(thing);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -32,6 +32,8 @@
|
||||
#define INTEGRATIONPLUGINGENERICTHINGS_H
|
||||
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "plugintimer.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
class IntegrationPluginGenericThings: public IntegrationPlugin
|
||||
@ -43,16 +45,18 @@ class IntegrationPluginGenericThings: public IntegrationPlugin
|
||||
|
||||
public:
|
||||
explicit IntegrationPluginGenericThings();
|
||||
void init() override;
|
||||
void setupThing(ThingSetupInfo *info) override;
|
||||
void executeAction(ThingActionInfo *info) override;
|
||||
void thingRemoved(Thing *thing) override;
|
||||
|
||||
private:
|
||||
QHash<Thing *, int> m_pulsesPerTimeframe;
|
||||
|
||||
double mapDoubleValue(double value, double fromMin, double fromMax, double toMin, double toMax);
|
||||
|
||||
QHash<Thing *, QTimer *> m_extendedBlindPercentageTimer;
|
||||
QHash<Thing *, QTimer *> m_venetianBlindAngleTimer;
|
||||
QHash<Thing *, QTimer *> m_smartMeterTimer;
|
||||
QHash<Thing *, uint> m_extendedBlindTargetPercentage;
|
||||
QHash<Thing *, int> m_venetianBlindTargetAngle;
|
||||
|
||||
|
||||
@ -693,6 +693,65 @@
|
||||
"ioType": "analogOutput"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "c3123967-f741-4fe1-a0d4-9a3e405d7e52",
|
||||
"name": "extendedSmartMeterConsumer",
|
||||
"displayName": "Impulse based energy meter",
|
||||
"createMethods": ["user"],
|
||||
"interfaces": ["extendedsmartmeterconsumer"],
|
||||
"settingsTypes": [
|
||||
{
|
||||
"id": "c361732b-68eb-447e-a434-e84031231871",
|
||||
"name": "impulsePerKwh",
|
||||
"displayName": "Impulse/kWh",
|
||||
"type": "int",
|
||||
"minValue": 1,
|
||||
"maxValue": 1000000,
|
||||
"defaultValue": 1000
|
||||
},
|
||||
{
|
||||
"id": "73c9acc3-8f76-40d7-a79b-a1f08bb308d4",
|
||||
"name": "impulseTimeframe",
|
||||
"displayName": "Timeframe for power calculation",
|
||||
"type": "int",
|
||||
"unit": "Seconds",
|
||||
"minValue": 1,
|
||||
"maxValue": 600,
|
||||
"defaultValue": 10
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "5983d714-5f80-42d8-bee2-9228b6382b3b",
|
||||
"name": "currentPower",
|
||||
"displayName": "Power",
|
||||
"displayNameEvent": "Power changed",
|
||||
"type": "double",
|
||||
"defaultValue": 0.00,
|
||||
"unit": "Watt"
|
||||
},
|
||||
{
|
||||
"id": "5821edb7-e6cb-4e5a-9d0b-3375126d3367",
|
||||
"name": "totalEnergyConsumed",
|
||||
"displayName": "Energy",
|
||||
"displayNameEvent": "Energy changed",
|
||||
"type": "double",
|
||||
"defaultValue": 0.00,
|
||||
"unit": "KiloWattHour"
|
||||
},
|
||||
{
|
||||
"id": "9cd7e5ca-f8f8-48d5-9785-911ae75158c3",
|
||||
"name": "impulseInput",
|
||||
"displayName": "Impulse input",
|
||||
"displayNameEvent": "Impulse input changed",
|
||||
"displayNameAction": "Set impulse input",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"writable": true,
|
||||
"ioType": "digitalOutput"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ The name of the StateType ({fcb700c4-5da8-4385-85b0-6616e807974e}) of ThingClass
|
||||
</message>
|
||||
<message>
|
||||
<source>Angle end to end time [MilliSecond]</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: venetianBlind, Type: thing, ID: {6c8340bf-7fd3-43e3-a75b-dfa2f6426e11})</extracomment>
|
||||
<extracomment>The name of the ParamType (ThingClass: venetianBlind, Type: settings, ID: {6c8340bf-7fd3-43e3-a75b-dfa2f6426e11})</extracomment>
|
||||
<translation>End- zu Endwinkelzeit</translation>
|
||||
</message>
|
||||
<message>
|
||||
@ -92,9 +92,9 @@ The name of the EventType ({59bfd575-709f-4e43-9726-de26e6d4ca8b}) of ThingClass
|
||||
</message>
|
||||
<message>
|
||||
<source>Closing time [MilliSecond]</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: venetianBlind, Type: thing, ID: {4c0bf07d-aaab-4f67-af65-00ceaefbaa84})
|
||||
<extracomment>The name of the ParamType (ThingClass: venetianBlind, Type: settings, ID: {4c0bf07d-aaab-4f67-af65-00ceaefbaa84})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: extendedBlind, Type: thing, ID: {27a95b8d-7f97-441b-a3be-0646c517cb06})</extracomment>
|
||||
The name of the ParamType (ThingClass: extendedBlind, Type: settings, ID: {27a95b8d-7f97-441b-a3be-0646c517cb06})</extracomment>
|
||||
<translation>Schließdauer [Millisekunden]</translation>
|
||||
</message>
|
||||
<message>
|
||||
@ -340,7 +340,11 @@ The name of the EventType ({181df603-d45f-4d3d-a358-97aa3e4ac0bd}) of ThingClass
|
||||
</message>
|
||||
<message>
|
||||
<source>Power</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: ventilation, ActionType: power, ID: {846711b7-ea5a-4c66-a267-001c60406509})
|
||||
<extracomment>The name of the ParamType (ThingClass: extendedSmartMeterConsumer, EventType: currentPower, ID: {5983d714-5f80-42d8-bee2-9228b6382b3b})
|
||||
----------
|
||||
The name of the StateType ({5983d714-5f80-42d8-bee2-9228b6382b3b}) of ThingClass extendedSmartMeterConsumer
|
||||
----------
|
||||
The name of the ParamType (ThingClass: ventilation, ActionType: power, ID: {846711b7-ea5a-4c66-a267-001c60406509})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: ventilation, EventType: power, ID: {846711b7-ea5a-4c66-a267-001c60406509})
|
||||
----------
|
||||
@ -379,7 +383,9 @@ The name of the StateType ({018038d7-1d02-4b17-8fe3-babca044b087}) of ThingClass
|
||||
</message>
|
||||
<message>
|
||||
<source>Power changed</source>
|
||||
<extracomment>The name of the EventType ({409b635e-a754-4b5c-b3f0-d1c5a0fb3f03}) of ThingClass heating
|
||||
<extracomment>The name of the EventType ({5983d714-5f80-42d8-bee2-9228b6382b3b}) of ThingClass extendedSmartMeterConsumer
|
||||
----------
|
||||
The name of the EventType ({409b635e-a754-4b5c-b3f0-d1c5a0fb3f03}) of ThingClass heating
|
||||
----------
|
||||
The name of the EventType ({8b6e4a67-6522-408b-b676-8d2f09ed2d54}) of ThingClass light
|
||||
----------
|
||||
@ -549,5 +555,62 @@ The name of the EventType ({0212a287-c5ae-4644-8803-adfdd8caeb9a}) of ThingClass
|
||||
<extracomment>The name of the vendor ({2062d64d-3232-433c-88bc-0d33c0ba2ba6})</extracomment>
|
||||
<translation>nymea</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Energy</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: extendedSmartMeterConsumer, EventType: totalEnergyConsumed, ID: {5821edb7-e6cb-4e5a-9d0b-3375126d3367})
|
||||
----------
|
||||
The name of the StateType ({5821edb7-e6cb-4e5a-9d0b-3375126d3367}) of ThingClass extendedSmartMeterConsumer</extracomment>
|
||||
<translation>Energie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Energy changed</source>
|
||||
<extracomment>The name of the EventType ({5821edb7-e6cb-4e5a-9d0b-3375126d3367}) of ThingClass extendedSmartMeterConsumer</extracomment>
|
||||
<translation>Energie geändert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Impulse/kWh</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: extendedSmartMeterConsumer, Type: settings, ID: {c361732b-68eb-447e-a434-e84031231871})</extracomment>
|
||||
<translation>Impulse/kWh</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Impulse input</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: extendedSmartMeterConsumer, ActionType: impulseInput, ID: {9cd7e5ca-f8f8-48d5-9785-911ae75158c3})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: extendedSmartMeterConsumer, EventType: impulseInput, ID: {9cd7e5ca-f8f8-48d5-9785-911ae75158c3})
|
||||
----------
|
||||
The name of the StateType ({9cd7e5ca-f8f8-48d5-9785-911ae75158c3}) of ThingClass extendedSmartMeterConsumer</extracomment>
|
||||
<translation>Impulseingang</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Impulse input changed</source>
|
||||
<extracomment>The name of the EventType ({9cd7e5ca-f8f8-48d5-9785-911ae75158c3}) of ThingClass extendedSmartMeterConsumer</extracomment>
|
||||
<translation>Impulseingang geändert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set impulse input</source>
|
||||
<extracomment>The name of the ActionType ({9cd7e5ca-f8f8-48d5-9785-911ae75158c3}) of ThingClass extendedSmartMeterConsumer</extracomment>
|
||||
<translation>Setze Impulseingang</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Timeframe for power calculation</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: extendedSmartMeterConsumer, Type: settings, ID: {73c9acc3-8f76-40d7-a79b-a1f08bb308d4})</extracomment>
|
||||
<translation>Zeitfenster für Leistungsberechnung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Impulse based energy meter</source>
|
||||
<extracomment>The name of the ThingClass ({c3123967-f741-4fe1-a0d4-9a3e405d7e52})</extracomment>
|
||||
<translation>Impulsbasierter Energiezähler</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>IntegrationPluginGenericThings</name>
|
||||
<message>
|
||||
<source>Invalid closing time</source>
|
||||
<translation>Ungültige Schließzeit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Invalid closing or angle time</source>
|
||||
<translation>Ungültige Schließ- oder Winkelstellzeit</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
||||
@ -28,7 +28,7 @@ The name of the StateType ({fcb700c4-5da8-4385-85b0-6616e807974e}) of ThingClass
|
||||
</message>
|
||||
<message>
|
||||
<source>Angle end to end time [MilliSecond]</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: venetianBlind, Type: thing, ID: {6c8340bf-7fd3-43e3-a75b-dfa2f6426e11})</extracomment>
|
||||
<extracomment>The name of the ParamType (ThingClass: venetianBlind, Type: settings, ID: {6c8340bf-7fd3-43e3-a75b-dfa2f6426e11})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@ -92,9 +92,9 @@ The name of the EventType ({59bfd575-709f-4e43-9726-de26e6d4ca8b}) of ThingClass
|
||||
</message>
|
||||
<message>
|
||||
<source>Closing time [MilliSecond]</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: venetianBlind, Type: thing, ID: {4c0bf07d-aaab-4f67-af65-00ceaefbaa84})
|
||||
<extracomment>The name of the ParamType (ThingClass: venetianBlind, Type: settings, ID: {4c0bf07d-aaab-4f67-af65-00ceaefbaa84})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: extendedBlind, Type: thing, ID: {27a95b8d-7f97-441b-a3be-0646c517cb06})</extracomment>
|
||||
The name of the ParamType (ThingClass: extendedBlind, Type: settings, ID: {27a95b8d-7f97-441b-a3be-0646c517cb06})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@ -340,7 +340,11 @@ The name of the EventType ({181df603-d45f-4d3d-a358-97aa3e4ac0bd}) of ThingClass
|
||||
</message>
|
||||
<message>
|
||||
<source>Power</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: ventilation, ActionType: power, ID: {846711b7-ea5a-4c66-a267-001c60406509})
|
||||
<extracomment>The name of the ParamType (ThingClass: extendedSmartMeterConsumer, EventType: currentPower, ID: {5983d714-5f80-42d8-bee2-9228b6382b3b})
|
||||
----------
|
||||
The name of the StateType ({5983d714-5f80-42d8-bee2-9228b6382b3b}) of ThingClass extendedSmartMeterConsumer
|
||||
----------
|
||||
The name of the ParamType (ThingClass: ventilation, ActionType: power, ID: {846711b7-ea5a-4c66-a267-001c60406509})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: ventilation, EventType: power, ID: {846711b7-ea5a-4c66-a267-001c60406509})
|
||||
----------
|
||||
@ -379,7 +383,9 @@ The name of the StateType ({018038d7-1d02-4b17-8fe3-babca044b087}) of ThingClass
|
||||
</message>
|
||||
<message>
|
||||
<source>Power changed</source>
|
||||
<extracomment>The name of the EventType ({409b635e-a754-4b5c-b3f0-d1c5a0fb3f03}) of ThingClass heating
|
||||
<extracomment>The name of the EventType ({5983d714-5f80-42d8-bee2-9228b6382b3b}) of ThingClass extendedSmartMeterConsumer
|
||||
----------
|
||||
The name of the EventType ({409b635e-a754-4b5c-b3f0-d1c5a0fb3f03}) of ThingClass heating
|
||||
----------
|
||||
The name of the EventType ({8b6e4a67-6522-408b-b676-8d2f09ed2d54}) of ThingClass light
|
||||
----------
|
||||
@ -549,5 +555,62 @@ The name of the EventType ({0212a287-c5ae-4644-8803-adfdd8caeb9a}) of ThingClass
|
||||
<extracomment>The name of the vendor ({2062d64d-3232-433c-88bc-0d33c0ba2ba6})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Energy</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: extendedSmartMeterConsumer, EventType: totalEnergyConsumed, ID: {5821edb7-e6cb-4e5a-9d0b-3375126d3367})
|
||||
----------
|
||||
The name of the StateType ({5821edb7-e6cb-4e5a-9d0b-3375126d3367}) of ThingClass extendedSmartMeterConsumer</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Energy changed</source>
|
||||
<extracomment>The name of the EventType ({5821edb7-e6cb-4e5a-9d0b-3375126d3367}) of ThingClass extendedSmartMeterConsumer</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Impulse/kWh</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: extendedSmartMeterConsumer, Type: settings, ID: {c361732b-68eb-447e-a434-e84031231871})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Impulse input</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: extendedSmartMeterConsumer, ActionType: impulseInput, ID: {9cd7e5ca-f8f8-48d5-9785-911ae75158c3})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: extendedSmartMeterConsumer, EventType: impulseInput, ID: {9cd7e5ca-f8f8-48d5-9785-911ae75158c3})
|
||||
----------
|
||||
The name of the StateType ({9cd7e5ca-f8f8-48d5-9785-911ae75158c3}) of ThingClass extendedSmartMeterConsumer</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Impulse input changed</source>
|
||||
<extracomment>The name of the EventType ({9cd7e5ca-f8f8-48d5-9785-911ae75158c3}) of ThingClass extendedSmartMeterConsumer</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set impulse input</source>
|
||||
<extracomment>The name of the ActionType ({9cd7e5ca-f8f8-48d5-9785-911ae75158c3}) of ThingClass extendedSmartMeterConsumer</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Timeframe for power calculation</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: extendedSmartMeterConsumer, Type: settings, ID: {73c9acc3-8f76-40d7-a79b-a1f08bb308d4})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Impulse based energy meter</source>
|
||||
<extracomment>The name of the ThingClass ({c3123967-f741-4fe1-a0d4-9a3e405d7e52})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>IntegrationPluginGenericThings</name>
|
||||
<message>
|
||||
<source>Invalid closing time</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Invalid closing or angle time</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user