mirror of https://github.com/nymea/nymea.git
408 lines
13 KiB
C++
408 lines
13 KiB
C++
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
*
|
|
* 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 General Public License Usage
|
|
* Alternatively, this project may be redistributed and/or modified under the
|
|
* terms of the GNU General Public License as published by the Free Software
|
|
* Foundation, GNU 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 General
|
|
* Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU 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 "nymeacore.h"
|
|
#include "loggingcategories.h"
|
|
#include "platform/platform.h"
|
|
#include "jsonrpc/jsonrpcserverimplementation.h"
|
|
#include "ruleengine/ruleengine.h"
|
|
#include "nymeasettings.h"
|
|
#include "tagging/tagsstorage.h"
|
|
#include "platform/platform.h"
|
|
#include "experiences/experiencemanager.h"
|
|
#include "platform/platformsystemcontroller.h"
|
|
#include "logging/logengineinfluxdb.h"
|
|
#include "scriptengine/scriptengine.h"
|
|
#include "jsonrpc/scriptshandler.h"
|
|
#include "jsonrpc/debughandler.h"
|
|
#include "version.h"
|
|
|
|
#include "integrations/thingmanagerimplementation.h"
|
|
#include "integrations/thing.h"
|
|
#include "integrations/thingactioninfo.h"
|
|
#include "integrations/browseractioninfo.h"
|
|
#include "integrations/browseritemactioninfo.h"
|
|
|
|
#include "zigbee/zigbeemanager.h"
|
|
|
|
#include "zwave/zwavemanager.h"
|
|
#include "hardware/modbus/modbusrtumanager.h"
|
|
#include "hardware/serialport/serialportmonitor.h"
|
|
|
|
#include <networkmanager.h>
|
|
|
|
#include <QDir>
|
|
#include <QCoreApplication>
|
|
|
|
NYMEA_LOGGING_CATEGORY(dcCore, "Core")
|
|
|
|
namespace nymeaserver {
|
|
|
|
NymeaCore* NymeaCore::s_instance = nullptr;
|
|
NymeaCore::ShutdownReason NymeaCore::s_shutdownReason = NymeaCore::ShutdownReasonTerm;
|
|
|
|
/*! Returns a pointer to the single \l{NymeaCore} instance. */
|
|
NymeaCore *NymeaCore::instance()
|
|
{
|
|
if (!s_instance) {
|
|
s_instance = new NymeaCore();
|
|
}
|
|
return s_instance;
|
|
}
|
|
|
|
/*! Constructs NymeaCore with the given \a parent. This is private.
|
|
Use \l{NymeaCore::instance()} to access the single instance.*/
|
|
NymeaCore::NymeaCore(QObject *parent) :
|
|
QObject(parent)
|
|
{
|
|
}
|
|
|
|
void NymeaCore::init(const QStringList &additionalInterfaces, bool disableLogEngine) {
|
|
qCDebug(dcCore()) << "Initializing NymeaCore";
|
|
|
|
qCDebug(dcPlatform()) << "Loading platform abstraction";
|
|
m_platform = new Platform(this);
|
|
|
|
qCDebug(dcCore()) << "Loading nymea configurations" << NymeaSettings(NymeaSettings::SettingsRoleGlobal).fileName();
|
|
m_configuration = new NymeaConfiguration(this);
|
|
|
|
qCDebug(dcCore()) << "Creating Time Manager";
|
|
// Migration path: nymea < 0.18 doesn't use system time zone but stores its own time zone in the config
|
|
// For migration, let's set the system's time zone to the config now to upgrade to the system time zone based nymea >= 0.18
|
|
if (QTimeZone(m_configuration->timeZone()).isValid()) {
|
|
if (m_platform->systemController()->setTimeZone(QTimeZone(m_configuration->timeZone()))) {
|
|
m_configuration->setTimeZone("");
|
|
}
|
|
}
|
|
m_timeManager = new TimeManager(this);
|
|
|
|
qCDebug(dcCore()) << "Creating User Manager";
|
|
m_userManager = new UserManager(NymeaSettings::settingsPath() + "/user-db.sqlite", this);
|
|
|
|
qCDebug(dcCore) << "Creating Server Manager";
|
|
m_serverManager = new ServerManager(m_platform, m_configuration, additionalInterfaces, this);
|
|
|
|
qCDebug(dcCore()) << "Create Serial Port Monitor";
|
|
m_serialPortMonitor = new SerialPortMonitor(this);
|
|
|
|
qCDebug(dcCore()) << "Create Zigbee Manager";
|
|
m_zigbeeManager = new ZigbeeManager(this);
|
|
|
|
qCDebug(dcCore()) << "Creating ZWave Manager";
|
|
m_zwaveManager = new ZWaveManager(m_serialPortMonitor, this);
|
|
|
|
qCDebug(dcCore()) << "Create Modbus RTU Manager";
|
|
m_modbusRtuManager = new ModbusRtuManager(m_serialPortMonitor, this);
|
|
|
|
qCDebug(dcCore) << "Creating Hardware Manager";
|
|
m_hardwareManager = new HardwareManagerImplementation(m_platform, m_serverManager->mqttBroker(), m_zigbeeManager, m_zwaveManager, m_modbusRtuManager, this);
|
|
|
|
qCDebug(dcCore) << "Creating Log Engine";
|
|
m_logEngine = new LogEngineInfluxDB(m_configuration->logDBHost(), m_configuration->logDBName(), m_configuration->logDBUser(), m_configuration->logDBPassword(), this);
|
|
if (disableLogEngine) {
|
|
m_logEngine->disable();
|
|
} else {
|
|
m_logEngine->enable();
|
|
}
|
|
|
|
m_logger = m_logEngine->registerLogSource("core", {"event"});
|
|
|
|
qCDebug(dcCore) << "Creating Thing Manager (locale:" << m_configuration->locale() << ")";
|
|
m_thingManager = new ThingManagerImplementation(m_hardwareManager, m_logEngine, m_configuration->locale(), this);
|
|
|
|
qCDebug(dcCore) << "Creating Rule Engine";
|
|
m_ruleEngine = new RuleEngine(m_thingManager, m_timeManager, m_logEngine, this);
|
|
|
|
qCDebug(dcCore()) << "Creating Script Engine";
|
|
m_scriptEngine = new scriptengine::ScriptEngine(m_thingManager, m_logEngine, this);
|
|
m_serverManager->jsonServer()->registerHandler(new ScriptsHandler(m_scriptEngine, m_scriptEngine));
|
|
|
|
qCDebug(dcCore()) << "Creating Tags Storage";
|
|
m_tagsStorage = new TagsStorage(m_thingManager, m_ruleEngine, this);
|
|
|
|
qCDebug(dcCore) << "Creating Network Manager";
|
|
m_networkManager = new NetworkManager(this);
|
|
m_networkManager->start();
|
|
|
|
qCDebug(dcCore) << "Creating Debug Server Handler";
|
|
m_debugServerHandler = new DebugServerHandler(this);
|
|
|
|
qCDebug(dcCore) << "Register Debug Handler";
|
|
m_serverManager->jsonServer()->registerHandler(new DebugHandler(m_serverManager->jsonServer()));
|
|
|
|
qCDebug(dcCore()) << "Loading experiences";
|
|
m_experienceManager = new ExperienceManager(m_thingManager, m_serverManager->jsonServer(), this);
|
|
|
|
connect(m_configuration, &NymeaConfiguration::serverNameChanged, m_serverManager, &ServerManager::setServerName);
|
|
|
|
connect(m_thingManager, &ThingManagerImplementation::loaded, this, &NymeaCore::thingManagerLoaded);
|
|
|
|
m_logger->log({"started"}, {{"version", NYMEA_VERSION_STRING}});
|
|
}
|
|
|
|
/*! Destructor of the \l{NymeaCore}. */
|
|
NymeaCore::~NymeaCore()
|
|
{
|
|
qCDebug(dcCore()) << "Shutting down NymeaCore";
|
|
m_logger->log({"stopped"}, {
|
|
{"version", NYMEA_VERSION_STRING},
|
|
{"shutdownReason", QMetaEnum::fromType<ShutdownReason>().valueToKey(s_shutdownReason)}
|
|
});
|
|
|
|
// Disconnect all signals/slots, we're going down now
|
|
m_timeManager->stopTimer();
|
|
m_timeManager->disconnect(this);
|
|
|
|
m_thingManager->disconnect(this);
|
|
m_ruleEngine->disconnect(this);
|
|
|
|
// Then stop magic from happening
|
|
qCDebug(dcCore) << "Shutting down \"Rule Engine\"";
|
|
delete m_ruleEngine;
|
|
|
|
qCDebug(dcCore()) << "Shutting down \"Experiences\"";
|
|
delete m_experienceManager;
|
|
|
|
// Next, ThingManager, so plugins don't access any resources any more.
|
|
qCDebug(dcCore) << "Shutting down \"Thing Manager\"";
|
|
delete m_thingManager;
|
|
|
|
// Destroy resources used by things
|
|
qCDebug(dcCore) << "Shutting down \"Server Manager\"";
|
|
delete m_serverManager;
|
|
|
|
qCDebug(dcCore()) << "Shutting down \"Hardware Manager\"";
|
|
delete m_hardwareManager;
|
|
|
|
// Now go ahead and clean up stuff.
|
|
qCDebug(dcCore) << "Shutting down \"Log Engine\"";
|
|
delete m_logEngine;
|
|
|
|
qCDebug(dcCore) << "Done shutting down NymeaCore";
|
|
}
|
|
|
|
void NymeaCore::destroy(ShutdownReason reason)
|
|
{
|
|
if (s_instance) {
|
|
s_shutdownReason = reason;
|
|
delete s_instance;
|
|
}
|
|
|
|
s_instance = nullptr;
|
|
}
|
|
|
|
NymeaConfiguration *NymeaCore::configuration() const
|
|
{
|
|
return m_configuration;
|
|
}
|
|
|
|
ThingManager *NymeaCore::thingManager() const
|
|
{
|
|
return m_thingManager;
|
|
}
|
|
|
|
RuleEngine *NymeaCore::ruleEngine() const
|
|
{
|
|
return m_ruleEngine;
|
|
}
|
|
|
|
ScriptEngine *NymeaCore::scriptEngine() const
|
|
{
|
|
return m_scriptEngine;
|
|
}
|
|
|
|
TimeManager *NymeaCore::timeManager() const
|
|
{
|
|
return m_timeManager;
|
|
}
|
|
|
|
ServerManager *NymeaCore::serverManager() const
|
|
{
|
|
return m_serverManager;
|
|
}
|
|
|
|
QStringList NymeaCore::getAvailableLanguages()
|
|
{
|
|
qCDebug(dcCore()) << "Loading translations from" << NymeaSettings::translationsPath();
|
|
|
|
QStringList searchPaths;
|
|
searchPaths << QCoreApplication::applicationDirPath() + "/../translations";
|
|
searchPaths << NymeaSettings::translationsPath();
|
|
|
|
QStringList translationFiles;
|
|
foreach (const QString &path, searchPaths) {
|
|
QDir translationDirectory(path);
|
|
translationDirectory.setNameFilters(QStringList() << "*.qm");
|
|
translationFiles = translationDirectory.entryList();
|
|
qCDebug(dcTranslations()) << translationFiles.count() << "translations in" << path;
|
|
if (translationFiles.count() > 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
QStringList availableLanguages;
|
|
foreach (QString translationFile, translationFiles) {
|
|
if (!translationFile.startsWith("nymead-"))
|
|
continue;
|
|
|
|
QString language = translationFile.remove("nymead-").remove(".qm");
|
|
QLocale languageLocale(language);
|
|
availableLanguages.append(languageLocale.name());
|
|
}
|
|
|
|
return availableLanguages;
|
|
}
|
|
|
|
QStringList NymeaCore::loggingFilters()
|
|
{
|
|
return nymeaLoggingCategories();
|
|
}
|
|
|
|
QStringList NymeaCore::loggingFiltersPlugins()
|
|
{
|
|
QStringList loggingFiltersPlugins;
|
|
foreach (const QJsonObject &pluginMetadata, ThingManagerImplementation::pluginsMetadata()) {
|
|
QString pluginName = pluginMetadata.value("name").toString();
|
|
loggingFiltersPlugins << pluginName.left(1).toUpper() + pluginName.mid(1);
|
|
}
|
|
return loggingFiltersPlugins;
|
|
}
|
|
|
|
BluetoothServer *NymeaCore::bluetoothServer() const
|
|
{
|
|
return m_serverManager->bluetoothServer();
|
|
}
|
|
|
|
NetworkManager *NymeaCore::networkManager() const
|
|
{
|
|
return m_networkManager;
|
|
}
|
|
|
|
UserManager *NymeaCore::userManager() const
|
|
{
|
|
return m_userManager;
|
|
}
|
|
|
|
CloudManager *NymeaCore::cloudManager() const
|
|
{
|
|
return m_cloudManager;
|
|
}
|
|
|
|
DebugServerHandler *NymeaCore::debugServerHandler() const
|
|
{
|
|
return m_debugServerHandler;
|
|
}
|
|
|
|
TagsStorage *NymeaCore::tagsStorage() const
|
|
{
|
|
return m_tagsStorage;
|
|
}
|
|
|
|
Platform *NymeaCore::platform() const
|
|
{
|
|
return m_platform;
|
|
}
|
|
|
|
ZigbeeManager *NymeaCore::zigbeeManager() const
|
|
{
|
|
return m_zigbeeManager;
|
|
}
|
|
|
|
ZWaveManager *NymeaCore::zwaveManager() const
|
|
{
|
|
return m_zwaveManager;
|
|
}
|
|
|
|
ModbusRtuManager *NymeaCore::modbusRtuManager() const
|
|
{
|
|
return m_modbusRtuManager;
|
|
}
|
|
|
|
ExperienceManager *NymeaCore::experienceManager() const
|
|
{
|
|
return m_experienceManager;
|
|
}
|
|
|
|
LogEngine *NymeaCore::logEngine() const
|
|
{
|
|
return m_logEngine;
|
|
}
|
|
|
|
JsonRPCServerImplementation *NymeaCore::jsonRPCServer() const
|
|
{
|
|
return m_serverManager->jsonServer();
|
|
}
|
|
|
|
void NymeaCore::thingManagerLoaded()
|
|
{
|
|
|
|
// Tell hardare resources we're done with loading stuff...
|
|
m_hardwareManager->thingsLoaded();
|
|
|
|
emit initialized();
|
|
|
|
// Do some houskeeping...
|
|
qCDebug(dcCore()) << "Starting housekeeping...";
|
|
QDateTime startTime = QDateTime::currentDateTime();
|
|
// ThingsFetchJob *job = m_logger->fetchThings();
|
|
// connect(job, &ThingsFetchJob::finished, m_thingManager, [this, job, startTime](){
|
|
// foreach (const ThingId &thingId, job->results()) {
|
|
// if (!m_thingManager->findConfiguredThing(thingId)) {
|
|
// qCDebug(dcCore()) << "Cleaning stale thing entries from log DB for thing id" << thingId;
|
|
// m_logger->removeThingLogs(thingId);
|
|
// }
|
|
// }
|
|
// qCDebug(dcCore()) << "Housekeeping done in" << startTime.msecsTo(QDateTime::currentDateTime()) << "ms.";
|
|
// });
|
|
|
|
foreach (const ThingId &thingId, m_ruleEngine->thingsInRules()) {
|
|
if (!m_thingManager->findConfiguredThing(thingId)) {
|
|
qCDebug(dcCore()) << "Cleaning stale rule entries for thing id" << thingId;
|
|
foreach (const RuleId &ruleId, m_ruleEngine->findRules(thingId)) {
|
|
m_ruleEngine->removeThingFromRule(ruleId, thingId);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (const Tag &tag, m_tagsStorage->tags()) {
|
|
if (!tag.ruleId().isNull() && !m_ruleEngine->findRule(tag.ruleId()).isValid()) {
|
|
qCDebug(dcCore()) << "Cleaning up stale rule tag" << tag;
|
|
m_tagsStorage->removeTag(tag);
|
|
}
|
|
if (!tag.thingId().isNull() && !m_thingManager->findConfiguredThing(tag.thingId())) {
|
|
qCDebug(dcCore()) << "Cleaning up stale thing tag" << tag.tagId();
|
|
m_tagsStorage->removeTag(tag);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|