Merge PR #498: Move simulation plugin to nymea-plugins-simulation repository

master
Jenkins nymea 2021-12-15 11:53:08 +01:00
commit 0479bb9ddb
12 changed files with 0 additions and 4787 deletions

16
debian/control vendored
View File

@ -961,21 +961,6 @@ Description: nymea.io plugin for Shelly devices
This package will install the nymea.io plugin for Shelly devices
Package: nymea-plugin-simulation
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
nymea-plugins-translations,
Description: nymea.io plugin for simulated devices
The nymea daemon is a plugin based IoT (Internet of Things) server. The
server works like a translator for devices, things and services and
allows them to interact.
With the powerful rule engine you are able to connect any device available
in the system and create individual scenes and behaviors for your environment.
.
This package will install the nymea.io plugin for simulated devices
Package: nymea-plugin-simpleheatpump
Architecture: any
Depends: ${shlibs:Depends},
@ -1400,7 +1385,6 @@ Package: nymea-plugins-all
Section: libs
Architecture: all
Depends: nymea-plugins,
nymea-plugin-simulation,
nymea-plugins-maker,
nymea-plugins-merkurboard,
Description: Plugins for nymea IoT server - Meta package for all plugins

View File

@ -1 +0,0 @@
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginsimulation.so

View File

@ -55,7 +55,6 @@ PLUGIN_DIRS = \
senic \
serialportcommander \
sgready \
simulation \
simpleheatpump \
sma \
somfytahoma \

View File

@ -1,3 +0,0 @@
# Simulation
This plugin contains many different simulated device in order to play with the system if you don't have any devices around or as a showcase for nymea.

View File

@ -1,923 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, 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 "integrationpluginsimulation.h"
#include "plugininfo.h"
#include <QtMath>
#include <QColor>
#include <QDateTime>
#include <QSettings>
IntegrationPluginSimulation::IntegrationPluginSimulation()
{
}
IntegrationPluginSimulation::~IntegrationPluginSimulation()
{
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer20Seconds);
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer5Min);
}
void IntegrationPluginSimulation::init()
{
// Seed the random generator with current time
qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
// Change some values every 20 seconds
m_pluginTimer20Seconds = hardwareManager()->pluginTimerManager()->registerTimer(20);
connect(m_pluginTimer20Seconds, &PluginTimer::timeout, this, &IntegrationPluginSimulation::onPluginTimer20Seconds);
// Change some values every 5 min
m_pluginTimer5Min = hardwareManager()->pluginTimerManager()->registerTimer(300);
connect(m_pluginTimer5Min, &PluginTimer::timeout, this, &IntegrationPluginSimulation::onPluginTimer5Minutes);
}
void IntegrationPluginSimulation::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
qCDebug(dcSimulation()) << "Set up thing" << thing->name();
if (thing->thingClassId() == garageGateThingClassId ||
thing->thingClassId() == extendedAwningThingClassId ||
thing->thingClassId() == extendedBlindThingClassId ||
thing->thingClassId() == venetianBlindThingClassId ||
thing->thingClassId() == rollerShutterThingClassId ||
thing->thingClassId() == fingerPrintSensorThingClassId ||
thing->thingClassId() == barcodeScannerThingClassId ||
thing->thingClassId() == contactSensorThingClassId ||
thing->thingClassId() == waterSensorThingClassId ||
thing->thingClassId() == cleaningRobotThingClassId) {
m_simulationTimers.insert(thing, new QTimer(thing));
connect(m_simulationTimers[thing], &QTimer::timeout, this, &IntegrationPluginSimulation::simulationTimerTimeout);
}
if (thing->thingClassId() == fingerPrintSensorThingClassId && thing->stateValue(fingerPrintSensorUsersStateTypeId).toStringList().count() > 0) {
m_simulationTimers.value(thing)->start(10000);
}
if (thing->thingClassId() == barcodeScannerThingClassId) {
m_simulationTimers.value(thing)->start(10000);
}
if (thing->thingClassId() == thermostatThingClassId) {
QTimer *t = new QTimer(thing);
connect(t, &QTimer::timeout, thing, [thing](){
double targetTemp = thing->stateValue(thermostatTargetTemperatureStateTypeId).toDouble();
double currentTemp = thing->stateValue(thermostatTemperatureStateTypeId).toDouble();
bool heatingOn = thing->stateValue(thermostatHeatingOnStateTypeId).toBool();
bool coolingOn = thing->stateValue(thermostatCoolingOnStateTypeId).toBool();
bool boost = thing->stateValue(thermostatBoostStateTypeId).toBool();
// When we're heating, temp increases slowly until it's up on par with target temp
if (heatingOn) {
double diff = targetTemp - currentTemp;
currentTemp += 0.005 + diff * (boost ? 0.2 : 0.1);
if (currentTemp >= targetTemp) {
thing->setStateValue(thermostatHeatingOnStateTypeId, false);
}
} else {
// Decrease 1% per interval to simulate drop of temperature (assuming it's cold outside)
currentTemp = currentTemp * 0.995;
// Start heating when we're more than 2 degrees lower than what we should be
if (currentTemp < targetTemp - 2) {
thing->setStateValue(thermostatHeatingOnStateTypeId, true);
}
}
if (coolingOn) {
double diff = targetTemp - currentTemp;
currentTemp += diff * 0.1;
if (currentTemp <= targetTemp) {
thing->setStateValue(thermostatCoolingOnStateTypeId, false);
}
} else {
if (currentTemp > targetTemp + 2) {
thing->setStateValue(thermostatCoolingOnStateTypeId, true);
}
}
thing->setStateValue(thermostatTemperatureStateTypeId, currentTemp);
});
t->start(10000);
}
if (thing->thingClassId() == contactSensorThingClassId) {
m_simulationTimers.value(thing)->start(10000);
}
if (thing->thingClassId() == waterSensorThingClassId) {
m_simulationTimers.value(thing)->start(10000);
}
info->finish(Thing::ThingErrorNoError);
}
void IntegrationPluginSimulation::thingRemoved(Thing *thing)
{
// Clean up any timers we may have for this thing
if (m_simulationTimers.contains(thing)) {
QTimer *t = m_simulationTimers.take(thing);
t->stop();
t->deleteLater();
}
}
void IntegrationPluginSimulation::executeAction(ThingActionInfo *info)
{
Thing *thing = info->thing();
Action action = info->action();
// Check the ThingClassId for "Simple Button"
if (thing->thingClassId() == simpleButtonThingClassId ) {
// check if this is the "press" action
if (action.actionTypeId() == simpleButtonTriggerActionTypeId) {
// Emit the "button pressed" event
qCDebug(dcSimulation()) << "Emit button pressed event for" << thing->name();
Event event(simpleButtonPressedEventTypeId, thing->id());
emit emitEvent(event);
return info->finish(Thing::ThingErrorNoError);
}
return info->finish(Thing::ThingErrorActionTypeNotFound);
}
// Check the ThingClassId for "Alternative Button"
if (thing->thingClassId() == alternativeButtonThingClassId) {
// check if this is the "set power" action
if (action.actionTypeId() == alternativeButtonPowerActionTypeId) {
// get the param value
Param powerParam = action.param(alternativeButtonPowerActionPowerParamTypeId);
bool power = powerParam.value().toBool();
qCDebug(dcSimulation()) << "Set power" << power << "for button" << thing->name();
// Set the "power" state
thing->setStateValue(alternativeButtonPowerStateTypeId, power);
return info->finish(Thing::ThingErrorNoError);
}
return info->finish(Thing::ThingErrorActionTypeNotFound);
}
if (thing->thingClassId() == heatingThingClassId) {
// check if this is the "set power" action
if (action.actionTypeId() == heatingPowerActionTypeId) {
// get the param value
Param powerParam = action.param(heatingPowerActionPowerParamTypeId);
bool power = powerParam.value().toBool();
qCDebug(dcSimulation()) << "Set power" << power << "for heating device" << thing->name();
thing->setStateValue(heatingPowerStateTypeId, power);
return info->finish(Thing::ThingErrorNoError);
} else if (action.actionTypeId() == heatingPercentageActionTypeId) {
// get the param value
Param percentageParam = action.param(heatingPercentageActionPercentageParamTypeId);
int percentage = percentageParam.value().toInt();
qCDebug(dcSimulation()) << "Set target temperature percentage" << percentage << "for heating device" << thing->name();
thing->setStateValue(heatingPercentageStateTypeId, percentage);
return info->finish(Thing::ThingErrorNoError);
}
return info->finish(Thing::ThingErrorActionTypeNotFound);
}
if (thing->thingClassId() == thermostatThingClassId) {
if (action.actionTypeId() == thermostatBoostActionTypeId) {
bool boost = action.param(thermostatBoostActionBoostParamTypeId).value().toBool();
qCDebug(dcSimulation()) << "Set boost" << boost << "for thermostat device" << thing->name();
thing->setStateValue(thermostatBoostStateTypeId, boost);
QTimer *t = new QTimer(thing);
t->setInterval(5 * 60 * 1000);
t->setSingleShot(true);
connect(t, &QTimer::timeout, t, &QTimer::deleteLater);
connect(t, &QTimer::timeout, thing, [thing](){
thing->setStateValue(thermostatBoostStateTypeId, false);
});
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == thermostatTargetTemperatureActionTypeId) {
double targetTemp = action.param(thermostatTargetTemperatureActionTargetTemperatureParamTypeId).value().toDouble();
qCDebug(dcSimulation()) << "Set targetTemp" << targetTemp << "for thermostat device" << thing->name();
thing->setStateValue(thermostatTargetTemperatureStateTypeId, targetTemp);
return info->finish(Thing::ThingErrorNoError);
}
}
if (thing->thingClassId() == evChargerThingClassId){
if (action.actionTypeId() == evChargerPowerActionTypeId){
// get the param value
Param powerParam = action.param(evChargerPowerActionPowerParamTypeId);
bool power = powerParam.value().toBool();
qCDebug(dcSimulation()) << "Set power" << power << "for heating device" << thing->name();
thing->setStateValue(evChargerPowerStateTypeId, power);
return info->finish(Thing::ThingErrorNoError);
} else if(action.actionTypeId() == evChargerMaxChargingCurrentActionTypeId){
// get the param value
Param maxChargeParam = action.param(evChargerMaxChargingCurrentActionMaxChargingCurrentParamTypeId);
double maxCharge = maxChargeParam.value().toDouble();
qCDebug(dcSimulation()) << "Set maximum charging current to" << maxCharge << "for EV Charger device" << thing->name();
thing->setStateValue(evChargerMaxChargingCurrentStateTypeId, maxCharge);
return info->finish(Thing::ThingErrorNoError);
}
return info->finish(Thing::ThingErrorActionTypeNotFound);
}
if(thing->thingClassId() == socketThingClassId){
if(action.actionTypeId() == socketPowerActionTypeId){
// get the param value
Param powerParam = action.param(socketPowerActionPowerParamTypeId);
bool power = powerParam.value().toBool();
// Set the "power" state
qCDebug(dcSimulation()) << "Set power" << power << "for socket device" << thing->name();
thing->setStateValue(socketPowerStateTypeId, power);
return info->finish(Thing::ThingErrorNoError);
}
return info->finish(Thing::ThingErrorActionTypeNotFound);
}
if(thing->thingClassId() == colorBulbThingClassId){
if(action.actionTypeId() == colorBulbBrightnessActionTypeId){
int brightness = action.param(colorBulbBrightnessActionBrightnessParamTypeId).value().toInt();
qCDebug(dcSimulation()) << "Set brightness" << brightness << "for color bulb" << thing->name();
thing->setStateValue(colorBulbBrightnessStateTypeId, brightness);
return info->finish(Thing::ThingErrorNoError);
} else if (action.actionTypeId() == colorBulbColorTemperatureActionTypeId){
int temperature = action.param(colorBulbColorTemperatureActionColorTemperatureParamTypeId).value().toInt();
qCDebug(dcSimulation()) << "Set color temperature" << temperature << "for color bulb" << thing->name();
thing->setStateValue(colorBulbColorTemperatureStateTypeId, temperature);
return info->finish(Thing::ThingErrorNoError);
} else if (action.actionTypeId() == colorBulbColorActionTypeId) {
QColor color = action.param(colorBulbColorActionColorParamTypeId).value().value<QColor>();
qCDebug(dcSimulation()) << "Set color" << color << "for color bulb" << thing->name();
thing->setStateValue(colorBulbColorStateTypeId, color);
return info->finish(Thing::ThingErrorNoError);
} else if (action.actionTypeId() == colorBulbPowerActionTypeId) {
bool power = action.param(colorBulbPowerActionPowerParamTypeId).value().toBool();
qCDebug(dcSimulation()) << "Set power" << power << "for color bulb" << thing->name();
thing->setStateValue(colorBulbPowerStateTypeId, power);
return info->finish(Thing::ThingErrorNoError);
}
return info->finish(Thing::ThingErrorActionTypeNotFound);
}
if (thing->thingClassId() == heatingRodThingClassId) {
if (action.actionTypeId() == heatingRodPowerActionTypeId) {
bool power = action.param(heatingRodPowerActionPowerParamTypeId).value().toBool();
qCDebug(dcSimulation()) << "Set power" << power << "for heating rod" << thing->name();
thing->setStateValue(heatingRodPowerStateTypeId, power);
return info->finish(Thing::ThingErrorNoError);
} else if (action.actionTypeId() == heatingRodPercentageActionTypeId) {
int percentage = action.param(heatingRodPercentageActionPercentageParamTypeId).value().toInt();
qCDebug(dcSimulation()) << "Set percentage" << percentage << "for heating rod" << thing->name();
thing->setStateValue(heatingRodPercentageStateTypeId, percentage);
return info->finish(Thing::ThingErrorNoError);
}
return info->finish(Thing::ThingErrorActionTypeNotFound);
}
if (thing->thingClassId() == batteryThingClassId) {
if (action.actionTypeId() == batteryMaxChargingActionTypeId) {
int maxCharging = action.param(batteryMaxChargingActionMaxChargingParamTypeId).value().toInt();
thing->setStateValue(batteryMaxChargingStateTypeId, maxCharging);
qCDebug(dcSimulation()) << "Set max charging power" << maxCharging << "for battery" << thing->name();
thing->setStateValue(batteryChargingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
return info->finish(Thing::ThingErrorActionTypeNotFound);
}
if (thing->thingClassId() == waterValveThingClassId) {
if (action.actionTypeId() == waterValvePowerActionTypeId) {
bool power = action.param(waterValvePowerActionPowerParamTypeId).value().toBool();
thing->setStateValue(waterValvePowerStateTypeId, power);
return info->finish(Thing::ThingErrorNoError);
}
return info->finish(Thing::ThingErrorActionTypeNotFound);
}
if (thing->thingClassId() == garageGateThingClassId) {
if (action.actionTypeId() == garageGateOpenActionTypeId) {
if (thing->stateValue(garageGateStateStateTypeId).toString() == "opening") {
qCDebug(dcSimulation()) << "Garage gate already opening.";
return info->finish(Thing::ThingErrorNoError);
}
if (thing->stateValue(garageGateStateStateTypeId).toString() == "open" &&
!thing->stateValue(garageGateIntermediatePositionStateTypeId).toBool()) {
qCDebug(dcSimulation()) << "Garage gate already open.";
return info->finish(Thing::ThingErrorNoError);
}
thing->setStateValue(garageGateStateStateTypeId, "opening");
thing->setStateValue(garageGateIntermediatePositionStateTypeId, true);
m_simulationTimers.value(thing)->start(5000);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == garageGateCloseActionTypeId) {
if (thing->stateValue(garageGateStateStateTypeId).toString() == "closing") {
qCDebug(dcSimulation()) << "Garage gate already closing.";
return info->finish(Thing::ThingErrorNoError);
}
if (thing->stateValue(garageGateStateStateTypeId).toString() == "closed" &&
!thing->stateValue(garageGateIntermediatePositionStateTypeId).toBool()) {
qCDebug(dcSimulation()) << "Garage gate already closed.";
return info->finish(Thing::ThingErrorNoError);
}
thing->setStateValue(garageGateStateStateTypeId, "closing");
thing->setStateValue(garageGateIntermediatePositionStateTypeId, true);
m_simulationTimers.value(thing)->start(5000);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == garageGateStopActionTypeId) {
if (thing->stateValue(garageGateStateStateTypeId).toString() == "opening" ||
thing->stateValue(garageGateStateStateTypeId).toString() == "closing") {
thing->setStateValue(garageGateStateStateTypeId, "open");
return info->finish(Thing::ThingErrorNoError);
}
qCDebug(dcSimulation()) << "Garage gate not moving";
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == garageGatePowerActionTypeId) {
bool power = action.param(garageGatePowerActionPowerParamTypeId).value().toBool();
thing->setStateValue(garageGatePowerStateTypeId, power);
return info->finish(Thing::ThingErrorNoError);
}
}
if (thing->thingClassId() == rollerShutterThingClassId) {
if (action.actionTypeId() == rollerShutterOpenActionTypeId) {
qCDebug(dcSimulation()) << "Opening roller shutter";
m_simulationTimers.value(thing)->setProperty("targetValue", 0);
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(rollerShutterMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == rollerShutterCloseActionTypeId) {
qCDebug(dcSimulation()) << "Closing roller shutter";
m_simulationTimers.value(thing)->setProperty("targetValue", 100);
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(rollerShutterMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == rollerShutterStopActionTypeId) {
qCDebug(dcSimulation()) << "Stopping roller shutter";
m_simulationTimers.value(thing)->stop();
thing->setStateValue(rollerShutterMovingStateTypeId, false);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == rollerShutterPercentageActionTypeId) {
qCDebug(dcSimulation()) << "Setting awning to" << action.param(rollerShutterPercentageActionPercentageParamTypeId);
m_simulationTimers.value(thing)->setProperty("targetValue", action.param(rollerShutterPercentageActionPercentageParamTypeId).value());
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(rollerShutterMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
}
if (thing->thingClassId() == extendedAwningThingClassId) {
if (action.actionTypeId() == extendedAwningOpenActionTypeId) {
qCDebug(dcSimulation()) << "Opening awning";
m_simulationTimers.value(thing)->setProperty("targetValue", 100);
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(extendedAwningMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == extendedAwningCloseActionTypeId) {
qCDebug(dcSimulation()) << "Closing awning";
m_simulationTimers.value(thing)->setProperty("targetValue", 0);
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(extendedAwningMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == extendedAwningStopActionTypeId) {
qCDebug(dcSimulation()) << "Stopping awning";
m_simulationTimers.value(thing)->stop();
thing->setStateValue(extendedAwningMovingStateTypeId, false);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == extendedAwningPercentageActionTypeId) {
qCDebug(dcSimulation()) << "Setting awning to" << action.param(extendedAwningPercentageActionPercentageParamTypeId);
m_simulationTimers.value(thing)->setProperty("targetValue", action.param(extendedAwningPercentageActionPercentageParamTypeId).value());
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(extendedAwningMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
}
if (thing->thingClassId() == fingerPrintSensorThingClassId) {
if (action.actionTypeId() == fingerPrintSensorAddUserActionTypeId) {
QStringList users = thing->stateValue(fingerPrintSensorUsersStateTypeId).toStringList();
QString username = action.param(fingerPrintSensorAddUserActionUserIdParamTypeId).value().toString();
QString finger = action.param(fingerPrintSensorAddUserActionFingerParamTypeId).value().toString();
QSettings settings;
settings.beginGroup(thing->id().toString());
QStringList usedFingers = settings.value(username).toStringList();
if (users.contains(username) && usedFingers.contains(finger)) {
return info->finish(Thing::ThingErrorDuplicateUuid);
}
QTimer::singleShot(5000, info, [this, info, thing, username, finger]() {
if (username.toLower().trimmed() == "john") {
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Fingerprint could not be scanned. Please try again."));
} else {
info->finish(Thing::ThingErrorNoError);
QStringList users = thing->stateValue(fingerPrintSensorUsersStateTypeId).toStringList();
if (!users.contains(username)) {
users.append(username);
thing->setStateValue(fingerPrintSensorUsersStateTypeId, users);
m_simulationTimers.value(thing)->start(10000);
}
QSettings settings;
settings.beginGroup(thing->id().toString());
QStringList usedFingers = settings.value(username).toStringList();
usedFingers.append(finger);
settings.setValue(username, usedFingers);
settings.endGroup();
}
});
return;
}
if (action.actionTypeId() == fingerPrintSensorRemoveUserActionTypeId) {
QStringList users = thing->stateValue(fingerPrintSensorUsersStateTypeId).toStringList();
QString username = action.params().first().value().toString();
if (!users.contains(username)) {
return info->finish(Thing::ThingErrorInvalidParameter);
}
users.removeAll(username);
thing->setStateValue(fingerPrintSensorUsersStateTypeId, users);
if (users.count() == 0) {
m_simulationTimers.value(thing)->stop();
}
return info->finish(Thing::ThingErrorNoError);
}
}
if (thing->thingClassId() == simpleBlindThingClassId) {
if (action.actionTypeId() == simpleBlindOpenActionTypeId) {
qCDebug(dcSimulation()) << "Opening simple blind";
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == simpleBlindCloseActionTypeId) {
qCDebug(dcSimulation()) << "Closing simple blind";
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == simpleBlindStopActionTypeId) {
qCDebug(dcSimulation()) << "Stopping simple blind";
return info->finish(Thing::ThingErrorNoError);
}
}
if (thing->thingClassId() == extendedBlindThingClassId) {
if (action.actionTypeId() == extendedBlindOpenActionTypeId) {
qCDebug(dcSimulation()) << "Opening extended blind";
m_simulationTimers.value(thing)->setProperty("targetValue", 0);
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(extendedBlindMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == extendedBlindCloseActionTypeId) {
qCDebug(dcSimulation()) << "Closing extended blind";
m_simulationTimers.value(thing)->setProperty("targetValue", 100);
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(extendedBlindMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == extendedBlindStopActionTypeId) {
qCDebug(dcSimulation()) << "Stopping extended blind";
m_simulationTimers.value(thing)->stop();
thing->setStateValue(extendedBlindMovingStateTypeId, false);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == extendedBlindPercentageActionTypeId) {
qCDebug(dcSimulation()) << "Setting extended blind to" << action.param(extendedBlindPercentageActionPercentageParamTypeId);
m_simulationTimers.value(thing)->setProperty("targetValue", action.param(extendedBlindPercentageActionPercentageParamTypeId).value());
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(extendedBlindMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
}
if (thing->thingClassId() == venetianBlindThingClassId) {
if (action.actionTypeId() == venetianBlindOpenActionTypeId) {
qCDebug(dcSimulation()) << "Opening venetian blind";
m_simulationTimers.value(thing)->setProperty("targetPosition", 0);
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(venetianBlindMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == venetianBlindCloseActionTypeId) {
qCDebug(dcSimulation()) << "Closing venetian blind";
m_simulationTimers.value(thing)->setProperty("targetPosition", 100);
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(venetianBlindMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == venetianBlindStopActionTypeId) {
qCDebug(dcSimulation()) << "Stopping venetian blind";
m_simulationTimers.value(thing)->stop();
m_simulationTimers.value(thing)->setProperty("targetPosition", thing->stateValue(venetianBlindPercentageStateTypeId).toInt());
m_simulationTimers.value(thing)->setProperty("targetAngle", thing->stateValue(venetianBlindAngleStateTypeId).toInt());
thing->setStateValue(venetianBlindMovingStateTypeId, false);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == venetianBlindPercentageActionTypeId) {
qCDebug(dcSimulation()) << "Setting venetian blind position to" << action.param(venetianBlindPercentageActionPercentageParamTypeId);
m_simulationTimers.value(thing)->setProperty("targetPosition", action.param(venetianBlindPercentageActionPercentageParamTypeId).value());
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(venetianBlindMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
if (action.actionTypeId() == venetianBlindAngleActionTypeId) {
qCDebug(dcSimulation()) << "Setting venetian blind angle to" << action.param(venetianBlindAngleActionAngleParamTypeId);
m_simulationTimers.value(thing)->setProperty("targetAngle", action.param(venetianBlindAngleActionAngleParamTypeId).value());
m_simulationTimers.value(thing)->start(500);
thing->setStateValue(venetianBlindMovingStateTypeId, true);
return info->finish(Thing::ThingErrorNoError);
}
}
if (thing->thingClassId() == cleaningRobotThingClassId) {
if (action.actionTypeId() == cleaningRobotStartCleaningActionTypeId) {
qCDebug(dcSimulation()) << "Starting to clean...";
thing->setStateValue(cleaningRobotRobotStateStateTypeId, "cleaning");
m_simulationTimers.value(thing)->stop();
info->finish(Thing::ThingErrorNoError);
return;
}
if (action.actionTypeId() == cleaningRobotPauseCleaningActionTypeId) {
qCDebug(dcSimulation()) << "Pausing...";
if (thing->stateValue(cleaningRobotRobotStateStateTypeId).toString() == "paused") {
thing->setStateValue(cleaningRobotRobotStateStateTypeId, "cleaning");
} else if (thing->stateValue(cleaningRobotRobotStateStateTypeId).toString() == "cleaning"){
thing->setStateValue(cleaningRobotRobotStateStateTypeId, "paused");
}
info->finish(Thing::ThingErrorNoError);
return;
}
if (action.actionTypeId() == cleaningRobotStopCleaningActionTypeId) {
qCDebug(dcSimulation()) << "Stopping.";
thing->setStateValue(cleaningRobotRobotStateStateTypeId, "stopped");
info->finish(Thing::ThingErrorNoError);
return;
}
if (action.actionTypeId() == cleaningRobotReturnToBaseActionTypeId) {
qCDebug(dcSimulation()) << "Returning to base...";
QString robotState = thing->stateValue(cleaningRobotRobotStateStateTypeId).toString();
if (robotState == "cleaning" || robotState == "paused" || robotState == "error") {
thing->setStateValue(cleaningRobotRobotStateStateTypeId, "traveling");
m_simulationTimers.value(thing)->start(5000);
}
info->finish(Thing::ThingErrorNoError);
return;
}
if (action.actionTypeId() == cleaningRobotSimulateErrorActionTypeId) {
thing->setStateValue(cleaningRobotRobotStateStateTypeId, "error");
thing->setStateValue(cleaningRobotErrorMessageStateTypeId, QT_TR_NOOP("Help me, I'm stuck!"));
info->finish(Thing::ThingErrorNoError);
return;
}
}
qCWarning(dcSimulation()) << "Unhandled thing class" << thing->thingClassId() << "for" << thing->name();
}
int IntegrationPluginSimulation::generateRandomIntValue(int min, int max)
{
int value = ((qrand() % ((max + 1) - min)) + min);
// qCDebug(dcSimulation()) << "Generateed random int value: [" << min << ", " << max << "] -->" << value;
return value;
}
double IntegrationPluginSimulation::generateRandomDoubleValue(double min, double max)
{
double value = generateRandomIntValue(static_cast<int>(min * 10), static_cast<int>(max * 10)) / 10.0;
// qCDebug(dcSimulation()) << "Generated random double value: [" << min << ", " << max << "] -->" << value;
return value;
}
bool IntegrationPluginSimulation::generateRandomBoolValue()
{
bool value = static_cast<bool>(generateRandomIntValue(0, 1));
// qCDebug(dcSimulation()) << "Generated random bool value:" << value;
return value;
}
qreal IntegrationPluginSimulation::generateSinValue(int min, int max, int hourOffset, int decimals)
{
// 00:00 : 23:99 = 0 : PI
// seconds of day : (60 * 60 * 24) = x : 2*PI
QDateTime d = QDateTime::currentDateTime();
int secondsPerDay = 60 * 60 * 24;
int offsetInSeconds = hourOffset * 60 * 60;
int secondsOfDay = d.time().msecsSinceStartOfDay() / 1000;
// add offset and wrap around
secondsOfDay = (secondsOfDay - offsetInSeconds) % secondsPerDay;
qreal interval = secondsOfDay * 2*M_PI / secondsPerDay;
qreal gain = 1.0 * (max - min) / 2;
qreal temp = (gain * qSin(interval)) + min + gain;
return QString::number(temp, 'f', decimals).toDouble();
}
qreal IntegrationPluginSimulation::generateBatteryValue(int chargeStartHour, int chargeDurationInMinutes)
{
QDateTime d = QDateTime::currentDateTime();
int secondsPerDay = 24 * 60 * 60;
int currentSecond = d.time().msecsSinceStartOfDay() / 1000;
int chargeStartSecond = chargeStartHour * 60 * 60;
int chargeEndSecond = chargeStartSecond + (chargeDurationInMinutes * 60);
int chargeDurationInSeconds = chargeDurationInMinutes * 60;
// should we be charging?
if (chargeStartSecond < currentSecond && currentSecond < chargeEndSecond) {
// Yep, charging...
int currentChargeSecond = currentSecond - chargeStartSecond;
// x : 100 = currentChargeSecond : chargeDurationInSeconds
return 100 * currentChargeSecond / chargeDurationInSeconds;
}
int dischargeDurationInSecs = secondsPerDay - chargeDurationInSeconds;
int currentDischargeSecond;
if (currentSecond < chargeStartSecond) {
currentDischargeSecond = currentSecond + (secondsPerDay - chargeEndSecond);
} else {
currentDischargeSecond = currentSecond - chargeEndSecond;
}
// 100 : x = dischargeDurationInSecs : currentDischargeSecond
return 100 - (100 * currentDischargeSecond / dischargeDurationInSecs);
}
qreal IntegrationPluginSimulation::generateNoisyRectangle(int min, int max, int maxNoise, int stablePeriodInMinutes, int &lastValue, QDateTime &lastChangeTimestamp)
{
QDateTime now = QDateTime::currentDateTime();
qCDebug(dcSimulation()) << "Generating noisy rect:" << min << "-" << max << "lastValue:" << lastValue << "lastUpdate" << lastChangeTimestamp << lastChangeTimestamp.secsTo(now) << lastChangeTimestamp.isValid();
if (!lastChangeTimestamp.isValid() || lastChangeTimestamp.secsTo(now) / 60 > stablePeriodInMinutes) {
lastChangeTimestamp.swap(now);
lastValue = min + qrand() % (max - min);
qCDebug(dcSimulation()) << "New last value:" << lastValue;
}
qreal noise = 0.1 * (qrand() % (maxNoise * 20) - maxNoise);
qreal ret = 1.0 * lastValue + noise;
return ret;
}
void IntegrationPluginSimulation::onPluginTimer20Seconds()
{
foreach (Thing *thing, myThings()) {
if (thing->thingClassId() == temperatureSensorThingClassId) {
// Temperature sensor
thing->setStateValue(temperatureSensorTemperatureStateTypeId, generateSinValue(18, 23, 8));
thing->setStateValue(temperatureSensorHumidityStateTypeId, generateSinValue(40, 55, 20));
thing->setStateValue(temperatureSensorBatteryLevelStateTypeId, generateBatteryValue(8, 10));
thing->setStateValue(temperatureSensorBatteryCriticalStateTypeId, thing->stateValue(temperatureSensorBatteryLevelStateTypeId).toInt() <= 25);
thing->setStateValue(temperatureSensorConnectedStateTypeId, true);
} else if (thing->thingClassId() == motionDetectorThingClassId) {
// Motion detector
thing->setStateValue(motionDetectorIsPresentStateTypeId, generateRandomBoolValue());
thing->setStateValue(motionDetectorBatteryLevelStateTypeId, generateBatteryValue(13, 1));
thing->setStateValue(motionDetectorBatteryCriticalStateTypeId, thing->stateValue(motionDetectorBatteryLevelStateTypeId).toInt() <= 30);
thing->setStateValue(motionDetectorConnectedStateTypeId, true);
} else if (thing->thingClassId() == waterSensorThingClassId) {
thing->setStateValue(waterSensorWaterDetectedStateTypeId, generateRandomBoolValue());
} else if (thing->thingClassId() == gardenSensorThingClassId) {
// Garden sensor
thing->setStateValue(gardenSensorTemperatureStateTypeId, generateSinValue(-4, 17, 5));
thing->setStateValue(gardenSensorSoilMoistureStateTypeId, generateSinValue(40, 60, 13));
thing->setStateValue(gardenSensorIlluminanceStateTypeId, generateSinValue(0, 80, 2));
thing->setStateValue(gardenSensorBatteryLevelStateTypeId, generateBatteryValue(9, 20));
thing->setStateValue(gardenSensorBatteryCriticalStateTypeId, thing->stateValue(gardenSensorBatteryLevelStateTypeId).toDouble() <= 30);
thing->setStateValue(gardenSensorConnectedStateTypeId, true);
} else if(thing->thingClassId() == netatmoIndoorThingClassId) {
// Netatmo
thing->setStateValue(netatmoIndoorUpdateTimeStateTypeId, QDateTime::currentDateTime().toTime_t());
thing->setStateValue(netatmoIndoorHumidityStateTypeId, generateSinValue(35, 45, 13));
thing->setStateValue(netatmoIndoorTemperatureStateTypeId, generateSinValue(20, 25, 3));
thing->setStateValue(netatmoIndoorPressureStateTypeId, generateSinValue(1003, 1008, 8));
thing->setStateValue(netatmoIndoorNoiseStateTypeId, generateRandomIntValue(40, 80));
thing->setStateValue(netatmoIndoorWifiStrengthStateTypeId, generateRandomIntValue(85, 95));
} else if (thing->thingClassId() == smartMeterThingClassId) {
thing->setStateValue(smartMeterConnectedStateTypeId, true);
int lastValue = thing->property("lastValue").toInt();
QDateTime lastUpdate = thing->property("lastUpdate").toDateTime();
qlonglong currentPower = generateNoisyRectangle(-2000, 100, 10, 5, lastValue, lastUpdate);
thing->setStateValue(smartMeterCurrentPowerStateTypeId, currentPower);
thing->setProperty("lastValue", lastValue);
thing->setProperty("lastUpdate", lastUpdate);
if (currentPower < 0) {
qreal consumptionKWH = 1.0 * currentPower * (1.0 * m_pluginTimer20Seconds->interval() / 1000 / 60 / 60) / 1000;
thing->setStateValue(smartMeterTotalEnergyConsumedStateTypeId, thing->stateValue(smartMeterTotalEnergyConsumedStateTypeId).toDouble() - consumptionKWH);
}
if (currentPower > 0) {
qreal consumptionKWH = 1.0 * currentPower * (1.0 * m_pluginTimer20Seconds->interval() / 1000 / 60 / 60) / 1000;
thing->setStateValue(smartMeterTotalEnergyProducedStateTypeId, thing->stateValue(smartMeterTotalEnergyProducedStateTypeId).toDouble() + consumptionKWH);
}
} else if (thing->thingClassId() == solarPanelThingClassId) {
int lastValue = thing->property("lastValue").toInt();
QDateTime lastUpdate = thing->property("lastUpdate").toDateTime();
qlonglong currentPower = generateNoisyRectangle(0, 2000, 50, 5, lastValue, lastUpdate);
thing->setStateValue(solarPanelCurrentPowerStateTypeId, currentPower);
thing->setProperty("lastValue", lastValue);
thing->setProperty("lastUpdate", lastUpdate);
qreal consumptionKWH = 1.0 * currentPower * (1.0 * m_pluginTimer20Seconds->interval() / 1000 / 60 / 60) / 1000;
thing->setStateValue(solarPanelTotalEnergyProducedStateTypeId, thing->stateValue(solarPanelTotalEnergyProducedStateTypeId).toDouble() + consumptionKWH);
} else if (thing->thingClassId() == cleaningRobotThingClassId) {
QString robotState = thing->stateValue(cleaningRobotRobotStateStateTypeId).toString();
int batteryLevel = thing->stateValue(cleaningRobotBatteryLevelStateTypeId).toInt();
bool charging = false;
bool pluggedIn = false;
if (robotState == "cleaning") {
batteryLevel -= 1;
if (batteryLevel < 5) {
robotState = "traveling";
m_simulationTimers.value(thing)->start(5000);
}
} else if (robotState == "docked") {
batteryLevel = qMin(100, batteryLevel + 2);
charging = batteryLevel < 100;
pluggedIn = true;
}
thing->setStateValue(cleaningRobotRobotStateStateTypeId, robotState);
thing->setStateValue(cleaningRobotBatteryLevelStateTypeId, batteryLevel);
thing->setStateValue(cleaningRobotBatteryCriticalStateTypeId, batteryLevel < 10);
thing->setStateValue(cleaningRobotChargingStateTypeId, charging);
thing->setStateValue(cleaningRobotPluggedInStateTypeId, pluggedIn);
}
}
}
void IntegrationPluginSimulation::onPluginTimer5Minutes()
{
foreach (Thing *thing, myThings()) {
if(thing->thingClassId() == netatmoIndoorThingClassId) {
// Note: should change between > 1000 co2 < 1000 for showcase, please do not change this behaviour
int currentValue = thing->stateValue(netatmoIndoorCo2StateTypeId).toInt();
if (currentValue < 1000) {
thing->setStateValue(netatmoIndoorCo2StateTypeId, generateRandomIntValue(1001, 1010));
} else {
thing->setStateValue(netatmoIndoorCo2StateTypeId, generateRandomIntValue(950, 999));
}
}
}
}
void IntegrationPluginSimulation::simulationTimerTimeout()
{
QTimer *t = static_cast<QTimer*>(sender());
Thing *thing = m_simulationTimers.key(t);
if (thing->thingClassId() == garageGateThingClassId) {
if (thing->stateValue(garageGateStateStateTypeId).toString() == "opening") {
thing->setStateValue(garageGateIntermediatePositionStateTypeId, false);
thing->setStateValue(garageGateStateStateTypeId, "open");
}
if (thing->stateValue(garageGateStateStateTypeId).toString() == "closing") {
thing->setStateValue(garageGateIntermediatePositionStateTypeId, false);
thing->setStateValue(garageGateStateStateTypeId, "closed");
}
} else if (thing->thingClassId() == extendedAwningThingClassId) {
int currentValue = thing->stateValue(extendedAwningPercentageStateTypeId).toInt();
int targetValue = t->property("targetValue").toInt();
int newValue = targetValue > currentValue ? qMin(targetValue, currentValue + 5) : qMax(targetValue, currentValue - 5);
thing->setStateValue(extendedAwningPercentageStateTypeId, newValue);
if (newValue == targetValue) {
t->stop();
thing->setStateValue(extendedAwningMovingStateTypeId, false);
}
} else if (thing->thingClassId() == extendedBlindThingClassId) {
int currentValue = thing->stateValue(extendedBlindPercentageStateTypeId).toInt();
int targetValue = t->property("targetValue").toInt();
int newValue = targetValue > currentValue ? qMin(targetValue, currentValue + 5) : qMax(targetValue, currentValue - 5);
thing->setStateValue(extendedBlindPercentageStateTypeId, newValue);
if (newValue == targetValue) {
t->stop();
thing->setStateValue(extendedBlindMovingStateTypeId, false);
}
} else if (thing->thingClassId() == venetianBlindThingClassId) {
int targetPosition = t->property("targetPosition").toInt();
int targetAngle = t->property("targetAngle").toInt();
int currentPosition = thing->stateValue(venetianBlindPercentageStateTypeId).toInt();
int currentAngle = thing->stateValue(venetianBlindAngleStateTypeId).toInt();
int newPosition = targetPosition > currentPosition ? qMin(targetPosition, currentPosition + 5) : qMax(targetPosition, currentPosition - 5);
thing->setStateValue(venetianBlindPercentageStateTypeId, newPosition);
int newAngle = targetAngle > currentAngle ? qMin(targetAngle, currentAngle + 5) : qMax(targetAngle, currentAngle - 5);
thing->setStateValue(venetianBlindAngleStateTypeId, newAngle);
if (newPosition == targetPosition && newAngle == targetAngle) {
t->stop();
thing->setStateValue(venetianBlindMovingStateTypeId, false);
}
} else if (thing->thingClassId() == rollerShutterThingClassId) {
int currentValue = thing->stateValue(rollerShutterPercentageStateTypeId).toInt();
int targetValue = t->property("targetValue").toInt();
int newValue = targetValue > currentValue ? qMin(targetValue, currentValue + 5) : qMax(targetValue, currentValue - 5);
thing->setStateValue(rollerShutterPercentageStateTypeId, newValue);
if (newValue == targetValue) {
t->stop();
thing->setStateValue(rollerShutterMovingStateTypeId, false);
}
} else if (thing->thingClassId() == fingerPrintSensorThingClassId) {
EventTypeId evt = qrand() % 2 == 0 ? fingerPrintSensorAccessGrantedEventTypeId : fingerPrintSensorAccessDeniedEventTypeId;
ParamList params;
if (evt == fingerPrintSensorAccessGrantedEventTypeId) {
QStringList users = thing->stateValue(fingerPrintSensorUsersStateTypeId).toStringList();
QString user = users.at(qrand() % users.count());
QSettings settings;
settings.beginGroup(thing->id().toString());
QStringList fingers = settings.value(user).toStringList();
params.append(Param(fingerPrintSensorAccessGrantedEventUserIdParamTypeId, user));
QString finger = fingers.at(qrand() % fingers.count());
params.append(Param(fingerPrintSensorAccessGrantedEventFingerParamTypeId, finger));
qCDebug(dcSimulation()) << "Emitting fingerprint accepted for user" << user << "and finger" << finger;
} else {
qCDebug(dcSimulation()) << "Emitting fingerprint denied";
}
Event event(evt, thing->id(), params);
emitEvent(event);
} else if (thing->thingClassId() == thermostatThingClassId) {
thing->setStateValue(thermostatBoostStateTypeId, false);
t->stop();
} else if (thing->thingClassId() == barcodeScannerThingClassId) {
QString code;
int codeIndex = thing->property("codeIndex").toInt();
switch (codeIndex) {
case 0:
code = "12345";
thing->setProperty("codeIndex", 1);
break;
case 1:
code = "23456";
thing->setProperty("codeIndex", 2);
break;
default:
code = "34567";
thing->setProperty("codeIndex", 0);
break;
}
ParamList params = ParamList() << Param(barcodeScannerCodeScannedEventContentParamTypeId, code);
Event event(barcodeScannerCodeScannedEventTypeId, thing->id(), params);
emit emitEvent(event);
} else if (thing->thingClassId() == contactSensorThingClassId) {
thing->setStateValue(contactSensorClosedStateTypeId, !thing->stateValue(contactSensorClosedStateTypeId).toBool());
thing->setStateValue(contactSensorBatteryLevelStateTypeId, thing->stateValue(contactSensorBatteryLevelStateTypeId).toInt()-1);
if (thing->stateValue(contactSensorBatteryLevelStateTypeId).toInt() == 0) {
thing->setStateValue(contactSensorBatteryLevelStateTypeId, 100);
thing->setStateValue(contactSensorBatteryCriticalStateTypeId, false);
} else if (thing->stateValue(contactSensorBatteryLevelStateTypeId).toInt() <= 20) {
thing->setStateValue(contactSensorBatteryCriticalStateTypeId, true);
} else {
thing->setStateValue(contactSensorBatteryCriticalStateTypeId, false);
}
} else if (thing->thingClassId() == waterSensorThingClassId) {
bool wet = qrand() > (RAND_MAX / 2);
thing->setStateValue(waterSensorWaterDetectedStateTypeId, wet);
} else if (thing->thingClassId() == cleaningRobotThingClassId) {
thing->setStateValue(cleaningRobotRobotStateStateTypeId, "docked");
}
}

View File

@ -1,79 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, 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 INTEGRATIONPLUGINSIMMULATION_H
#define INTEGRATIONPLUGINSIMMULATION_H
#include "integrations/integrationplugin.h"
#include "plugintimer.h"
#include <QDateTime>
#include "extern-plugininfo.h"
class IntegrationPluginSimulation : public IntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginsimulation.json")
Q_INTERFACES(IntegrationPlugin)
public:
explicit IntegrationPluginSimulation();
~IntegrationPluginSimulation();
void init() override;
void setupThing(ThingSetupInfo *info) override;
void thingRemoved(Thing *thing) override;
void executeAction(ThingActionInfo *info) override;
private:
PluginTimer *m_pluginTimer20Seconds = nullptr;
PluginTimer *m_pluginTimer5Min = nullptr;
int generateRandomIntValue(int min, int max);
double generateRandomDoubleValue(double min, double max);
bool generateRandomBoolValue();
// Generates values in a sin curve from min to max, moving the start by hourOffset from midnight
qreal generateSinValue(int min, int max, int hourOffset, int decimals = 2);
qreal generateBatteryValue(int chargeStartHour, int chargeDurationInMinutes);
qreal generateNoisyRectangle(int min, int max, int noise, int stablePeriodInMinutes, int &lastValue, QDateTime &lastChangeTimestamp);
QHash<Thing*, QTimer*> m_simulationTimers;
private slots:
void onPluginTimer20Seconds();
void onPluginTimer5Minutes();
void simulationTimerTimeout();
};
#endif // INTEGRATIONPLUGINSIMMULATION_H

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
{
"title": "Simulation",
"tagline": "Simulate different thing types.",
"icon": "simulation.svg",
"stability": "consumer",
"offline": false,
"technologies": [
],
"categories": [
"tool"
]
}

View File

@ -1,9 +0,0 @@
include(../plugins.pri)
TARGET = $$qtLibraryTarget(nymea_integrationpluginsimulation)
SOURCES += \
integrationpluginsimulation.cpp \
HEADERS += \
integrationpluginsimulation.h \

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M447.1,256.2C401.8,204,339.2,144,256,144c-33.6,0-64.4,9.5-96.9,29.8C131.7,191,103.6,215.2,65,255l-1,1l6.7,6.9
C125.8,319.3,173.4,368,256,368c36.5,0,71.9-11.9,108.2-36.4c30.9-20.9,57.2-47.4,78.3-68.8l5.5-5.5L447.1,256.2z M256,160
c33.1,0,64.9,9.5,97.2,30.6c23.9,15.6,47.4,36.7,73.7,66.1C388.6,295.4,331.1,352,256,352c-34.2,0-64.2-8.4-94.2-28.2
c-27.5-18.1-52.3-43.3-76.2-67.8C144.7,196.3,194,160,256,160z"/>
<path d="M256,336c44.1,0,80-35.9,80-80c0-44.1-35.9-80-80-80c-44.1,0-80,35.9-80,80C176,300.1,211.9,336,256,336z M256,192.3
c35.2,0,64,28.6,64,63.7c0,35.1-28.8,63.7-64,63.7c-35.2,0-63.9-28.6-63.9-63.7C192.1,220.9,220.8,192.3,256,192.3z"/>
</g>
<path d="M288,256L288,256c0,17.5-14.4,32-31.8,32S224,272.8,224,255.3s15.8-31.3,32-31.3l0-16c-26.5,0-47.9,21.6-47.9,48.2
c0,26.6,21.5,48.1,47.9,48.1s48-21.6,48-48.1V256H288z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB