From 6d742e60db06af9c235b90cd54354b3b7a9a47c4 Mon Sep 17 00:00:00 2001 From: Carl Philipp Klemm Date: Sun, 1 Mar 2026 14:39:27 +0100 Subject: [PATCH] Major wip refactor Allow running without gui Remove serialPortMultiplexer broadcast use Add TcpServer and TcpClient Introduce the concept of an item source --- SHinterface.pro | 24 +-- src/actors/alarmtime.cpp | 6 +- src/items/auxitem.cpp | 3 +- src/items/auxitem.h | 7 +- src/items/item.cpp | 84 +++++++--- src/items/item.h | 21 +-- src/items/itemsource.cpp | 5 + src/items/itemsource.h | 24 +++ src/items/itemstore.cpp | 153 ++++++++++-------- src/items/itemstore.h | 22 ++- src/items/messageitem.cpp | 3 +- src/items/messageitem.h | 10 +- src/items/poweritem.cpp | 7 +- src/items/poweritem.h | 8 +- src/items/relay.cpp | 9 +- src/items/relay.h | 9 +- src/items/rgbitem.cpp | 3 +- src/items/rgbitem.h | 7 +- src/items/systemitem.cpp | 2 +- src/items/systemitem.h | 11 +- src/main.cpp | 219 ++++++++++++++++---------- src/mainobject.cpp | 209 ++++++++----------------- src/mainobject.h | 77 ++++----- src/microcontroller.cpp | 26 ++-- src/microcontroller.h | 11 +- src/programmode.cpp | 3 + src/programmode.h | 13 ++ src/sensors/ocupancysensor.cpp | 62 -------- src/sensors/ocupancysensor.h | 33 ---- src/sensors/pipewiresensor.cpp | 74 --------- src/sensors/pipewiresensor.h | 40 ----- src/sensors/sensor.h | 41 ++++- src/sensors/speakersensor.cpp | 59 ------- src/sensors/speakersensor.h | 45 ------ src/tcpserver.cpp | 277 +++++++++++++++++++++++++++++++++ src/tcpserver.h | 89 +++++++++++ src/ui/mainwindow.cpp | 44 ++---- src/ui/mainwindow.h | 13 +- 38 files changed, 928 insertions(+), 825 deletions(-) create mode 100644 src/items/itemsource.cpp create mode 100644 src/items/itemsource.h create mode 100644 src/programmode.cpp create mode 100644 src/programmode.h delete mode 100644 src/sensors/ocupancysensor.cpp delete mode 100644 src/sensors/ocupancysensor.h delete mode 100644 src/sensors/pipewiresensor.cpp delete mode 100644 src/sensors/pipewiresensor.h delete mode 100644 src/sensors/speakersensor.cpp delete mode 100644 src/sensors/speakersensor.h create mode 100644 src/tcpserver.cpp create mode 100644 src/tcpserver.h diff --git a/SHinterface.pro b/SHinterface.pro index 55a7b33..e2954c7 100644 --- a/SHinterface.pro +++ b/SHinterface.pro @@ -4,7 +4,7 @@ # #------------------------------------------------- -QT += core gui widgets network multimedia httpserver +QT += core gui widgets network multimedia QT += serialport @@ -26,7 +26,7 @@ QMAKE_CXXFLAGS += -std=c++17 -O2 SOURCES += \ src/actors/factoractor.cpp \ src/actors/polynomalactor.cpp \ - src/broadcast.cpp \ + src/tcpserver.cpp \ src/iomuliplexer.cpp \ src/items/messageitem.cpp \ src/items/systemitem.cpp \ @@ -61,27 +61,29 @@ SOURCES += \ SOURCES += \ src/sensors/sensor.cpp \ - src/sensors/speakersensor.cpp \ src/sensors/sunsensor.cpp \ - src/sensors/ocupancysensor.cpp SOURCES += \ src/items/relay.cpp \ src/items/item.cpp \ src/items/itemstore.cpp \ src/items/auxitem.cpp \ - src/items/rgbitem.cpp + src/items/rgbitem.cpp \ + src/items/itemsource.cpp SOURCES += \ src/main.cpp \ src/microcontroller.cpp \ - src/sun.cpp + src/sun.cpp \ + src/programmode.cpp HEADERS += \ src/actors/factoractor.h \ src/actors/polynomalactor.h \ - src/broadcast.h \ + src/items/itemsource.h \ + src/programmode.h \ + src/tcpserver.h \ src/iomuliplexer.h \ src/items/messageitem.h \ src/items/systemitem.h \ @@ -116,20 +118,20 @@ HEADERS += \ HEADERS += \ src/sensors/sensor.h \ - src/sensors/speakersensor.h \ src/sensors/sunsensor.h \ - src/sensors/ocupancysensor.h HEADERS += \ src/items/relay.h \ src/items/item.h \ src/items/itemstore.h \ src/items/auxitem.h \ - src/items/rgbitem.h + src/items/rgbitem.h \ + src/items/itemsource.h HEADERS += \ src/microcontroller.h \ - src/sun.h + src/sun.h \ + src/programmode.h FORMS += \ src/ui/actorwidgets/factoractorwidget.ui \ diff --git a/src/actors/alarmtime.cpp b/src/actors/alarmtime.cpp index ff26813..0f38f27 100644 --- a/src/actors/alarmtime.cpp +++ b/src/actors/alarmtime.cpp @@ -4,17 +4,17 @@ AlarmTime::AlarmTime(const QDateTime time, QObject *parent) : Actor(parent), tim { connect(&timer, SIGNAL(timeout()), this, SLOT(doTick())); timer.setInterval(1000); - run(); + AlarmTime::run(); } AlarmTime::~AlarmTime() { - makeInactive(); + AlarmTime::makeInactive(); } void AlarmTime::run() { - makeInactive(); + AlarmTime::makeInactive(); active = true; timer.start(); diff --git a/src/items/auxitem.cpp b/src/items/auxitem.cpp index 860a121..42f3efd 100644 --- a/src/items/auxitem.cpp +++ b/src/items/auxitem.cpp @@ -6,9 +6,8 @@ AuxItem::AuxItem(Microcontroller* micro, uint32_t itemIdIn, QString name, uint8 } -void AuxItem::setValue(uint8_t value) +void AuxItem::enactValue(uint8_t value) { - Item::setValue(value); micro_->setAuxPwm(value); } diff --git a/src/items/auxitem.h b/src/items/auxitem.h index b9347f9..0483c39 100644 --- a/src/items/auxitem.h +++ b/src/items/auxitem.h @@ -9,13 +9,12 @@ class AuxItem: public Item private: Microcontroller* micro_; -public slots: - - virtual void setValue(uint8_t value); +protected: + virtual void enactValue(uint8_t value) override; public: AuxItem(Microcontroller* micro, uint32_t itemIdIn = QRandomGenerator::global()->generate(), QString name = "", uint8_t value = 0, QObject* parent = nullptr); - virtual void store(QJsonObject& json); + virtual void store(QJsonObject& json) override; }; diff --git a/src/items/item.cpp b/src/items/item.cpp index 862834c..2596b4f 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -1,10 +1,12 @@ #include "item.h" +#include "src/actors/sensoractor.h" +#include "src/actors/regulator.h" +#include "src/actors/polynomalactor.h" +#include "src/programmode.h" #include "relay.h" -#include "../microcontroller.h" -#include "../actors/sensoractor.h" -#include "../actors/regulator.h" -#include "../actors/polynomalactor.h" +#include "messageitem.h" +#include "systemitem.h" #include @@ -33,11 +35,25 @@ uint32_t ItemData::id() const return itemId_; } +void ItemData::store(QJsonObject &json) +{ + json["Name"] = name_; + json["ItemId"] = static_cast(itemId_); + json["Value"] = static_cast(value_); +} + +void ItemData::load(const QJsonObject &json, const bool preserve) +{ + if(!preserve) + { + name_ = json["Name"].toString(name_); + itemId_ = static_cast(json["ItemId"].toDouble(0)); + } +} + //item -bool Item::secondaryFlag = false; - Item::Item(uint32_t itemIdIn, QString name, uint8_t value, QObject *parent): QObject(parent), ItemData (itemIdIn, name, value) { @@ -55,8 +71,7 @@ Item::~Item() void Item::store(QJsonObject &json) { - json["Name"] = name_; - json["ItemId"] = static_cast(itemId_); + ItemData::store(json); json["override"] = override_; QJsonArray actorsArray; for(size_t i = 0; i < actors_.size(); ++i) @@ -73,11 +88,7 @@ void Item::store(QJsonObject &json) void Item::load(const QJsonObject &json, const bool preserve) { - if(!preserve) - { - name_ = json["Name"].toString(name_); - itemId_ = static_cast(json["ItemId"].toDouble(0)); - } + ItemData::load(json, preserve); override_ = json["override"].toBool(false); const QJsonArray actorsArray(json["Actors"].toArray(QJsonArray())); for(int i = 0; i < actorsArray.size(); ++i) @@ -92,28 +103,35 @@ void Item::load(const QJsonObject &json, const bool preserve) void Item::actorSetValue(uint8_t value) { - if(!override_) setValue(value); + if(!override_ && (programMode == PROGRAM_MODE_PRIMARY || programMode == PROGRAM_MODE_HEADLESS_PRIMARY)) + setValue(value); } void Item::setValue(uint8_t value) { - value_ = value; - valueChanged(value_); + informValue(value); + if(programMode == PROGRAM_MODE_PRIMARY || programMode == PROGRAM_MODE_HEADLESS_PRIMARY) + enactValue(value); } void Item::informValue(uint8_t value) { - Item::setValue(value); + value_ = value; + valueChanged(value_); + updated(*this); +} + +void Item::enactValue(uint8_t value) +{ + (void)value; } void Item::addActor(std::shared_ptr actor) { actor->setParent(this); actors_.push_back(actor); - if(!secondaryFlag) - { + if(programMode == PROGRAM_MODE_PRIMARY || programMode == PROGRAM_MODE_HEADLESS_PRIMARY) connect(actor.get(), &Actor::sigValue, this, &Item::actorSetValue); - } connect(this, &Item::valueChanged, actor.get(), &Actor::onValueChanged); std::shared_ptr sensorActor = std::dynamic_pointer_cast(actor); @@ -167,5 +185,29 @@ bool Item::hasActors() void Item::setActorsActive(bool in) { - for(unsigned i = 0; i < actors_.size(); i++) in ? actors_[i]->makeActive() : actors_[i]->makeInactive(); + for(unsigned i = 0; i < actors_.size(); i++) + in ? actors_[i]->makeActive() : actors_[i]->makeInactive(); +} + +std::shared_ptr Item::loadItem(const QJsonObject& json) +{ + std::shared_ptr newItem = nullptr; + if(json["Type"].toString("") == "Relay") + { + newItem = std::shared_ptr(new Relay); + } + else if(json["Type"].toString("") == "Message") + { + newItem = std::shared_ptr(new MessageItem); + } + else if(json["Type"].toString("") == "System") + { + newItem = std::shared_ptr(new SystemItem); + } + else if(json["Type"].toString("") == "Aux") + { + } + if(newItem) + newItem->load(json); + return newItem; } diff --git a/src/items/item.h b/src/items/item.h index 18aa0cc..bfa43f6 100644 --- a/src/items/item.h +++ b/src/items/item.h @@ -16,16 +16,15 @@ protected: uint32_t itemId_; public: - ItemData(uint32_t itemIdIn = QRandomGenerator::global()->generate(), QString name = "Item", uint8_t value = 0); inline bool operator==(const ItemData& in) const { - return itemId_==in.itemId_; + return itemId_ == in.itemId_; } inline bool operator!=(const ItemData& in) const { - return itemId_!=in.itemId_; + return itemId_ != in.itemId_; } uint32_t id() const; @@ -33,6 +32,8 @@ public: void setName(QString name); uint8_t getValue() const; virtual QString getName() const; + virtual void store(QJsonObject& json); + virtual void load(const QJsonObject& json, const bool preserve = false); }; @@ -44,20 +45,15 @@ private: bool override_ = false; -public: - - static bool secondaryFlag; - signals: - void valueChanged(uint8_t value); + void updated(ItemData data); private slots: virtual void actorSetValue(uint8_t value); public slots: - - virtual void setValue(uint8_t value); + void setValue(uint8_t value); public: @@ -80,5 +76,10 @@ public: virtual void store(QJsonObject& json); virtual void load(const QJsonObject& json, const bool preserve = false); + static std::shared_ptr loadItem(const QJsonObject& json); + +protected: + virtual void enactValue(uint8_t value); + }; diff --git a/src/items/itemsource.cpp b/src/items/itemsource.cpp new file mode 100644 index 0000000..1a223dc --- /dev/null +++ b/src/items/itemsource.cpp @@ -0,0 +1,5 @@ +#include "itemsource.h" + +ItemSource::ItemSource(QObject *parent) + : QObject{parent} +{} diff --git a/src/items/itemsource.h b/src/items/itemsource.h new file mode 100644 index 0000000..8e26c18 --- /dev/null +++ b/src/items/itemsource.h @@ -0,0 +1,24 @@ +#ifndef ITEMSOURCE_H +#define ITEMSOURCE_H + +#include +#include +#include + +#include "item.h" + +class ItemSource : public QObject +{ + Q_OBJECT +public: + explicit ItemSource(QObject *parent = nullptr); + +public slots: + virtual void refresh() = 0; + +signals: + void gotItems(std::vector> items, bool inform = true); + void updateItems(std::vector items, bool inform = true); +}; + +#endif // ITEMSOURCE_H diff --git a/src/items/itemstore.cpp b/src/items/itemstore.cpp index f3e4ab1..e681a97 100644 --- a/src/items/itemstore.cpp +++ b/src/items/itemstore.cpp @@ -1,52 +1,42 @@ #include "itemstore.h" -#include "relay.h" -#include "messageitem.h" -#include "systemitem.h" #include +#include ItemStore::ItemStore(QObject *parent): QObject(parent) { } -void ItemStore::addItem(std::shared_ptr item) +void ItemStore::addItem(std::shared_ptr item, bool inform) { - bool mached = false; - for(unsigned i = 0; i < items_.size(); i++ ) if(*items_[i] == *item) mached = true; - if(!mached) + std::shared_ptr matched = nullptr; + for(unsigned i = 0; i < items_.size(); i++ ) + { + if(*items_[i] == *item) + { + matched = items_[i]; + break; + } + } + if(!matched) { items_.push_back(std::shared_ptr(item)); + connect(item.get(), &Item::updated, this, &ItemStore::itemUpdateSlot); + qDebug()<<"Item"<getName()<<"added"; itemAdded(std::weak_ptr(items_.back())); } + else if(item->getValue() != matched->getValue()) + { + if(inform) + matched->informValue(item->getValue()); + else + matched->setValue(item->getValue()); + } } -void ItemStore::addItems(const std::vector>& itemIn) +void ItemStore::addItems(const std::vector>& itemIn, bool inform) { - for(unsigned i = 0; i < items_.size(); i++ ) - { - if(Relay* relay = dynamic_cast(items_[i].get())) - { - bool mached = false; - for(unsigned j = 0; j < itemIn.size(); j++) if(*(items_[i]) == *(itemIn[j])) - { - mached = true; - if(itemIn[j]->getValue() != items_[i]->getValue()) items_[i]->informValue(itemIn[j]->getValue()); - Relay* relayIn = dynamic_cast(itemIn[j].get()); - if(relayIn) - { - if(relay->getId() != relayIn->getId()) relay->setId(relayIn->getId()); - } - - } - if(!mached) - { - itemDeleted(*items_[i].get()); - items_.erase(items_.begin()+i); - } - } - } - - for(unsigned j = 0; j < itemIn.size(); j++)addItem(itemIn[j]); - + for(unsigned j = 0; j < itemIn.size(); j++) + addItem(itemIn[j], inform); } void ItemStore::removeItem(const ItemData& item) @@ -55,13 +45,14 @@ void ItemStore::removeItem(const ItemData& item) { if(item == *items_[j]) { + qDebug()<<"Item"< items, bool inform) { + for(const ItemData& item : items) + updateItem(item, inform); +} + +void ItemStore::updateItem(const ItemData& item, bool inform) +{ for(unsigned i = 0; i < items_.size(); i++ ) { if(items_[i]->operator==(item)) { - - if(items_[i]->getValue() != item.getValue())items_[i]->informValue(item.getValue()); + if(items_[i]->getValue() != item.getValue()) + { + if(inform) + items_[i]->informValue(item.getValue()); + else + items_[i]->setValue(item.getValue()); + } + qDebug()<<"Item"<getName()<<"updated"; + itemUpdated(items_[i]); } - } - } void ItemStore::store(QJsonObject& json) @@ -101,30 +103,51 @@ void ItemStore::load(const QJsonObject& json) const QJsonArray itemsArray(json["Items"].toArray(QJsonArray())); for(int i = 0; i < itemsArray.size(); ++i) { - if(itemsArray[i].isObject()) - { - const QJsonObject itemObject = itemsArray[i].toObject(); - std::shared_ptr newItem; - if(itemObject["Type"].toString("") == "Relay") - { - newItem = std::shared_ptr(new Relay()); - } - else if(itemObject["Type"].toString("") == "Message") - { - newItem = std::shared_ptr(new MessageItem); - } - else if(itemObject["Type"].toString("") == "System") - { - newItem = std::shared_ptr(new SystemItem()); - } - else if(itemObject["Type"].toString("") == "Aux") - { - } - if(newItem) - { - newItem->load(itemObject); - addItem(newItem); - } - } + if(!itemsArray[i].isObject()) + continue; + + const QJsonObject itemObject = itemsArray[i].toObject(); + std::shared_ptr newItem = Item::loadItem(itemObject); + if(newItem) + addItem(newItem); } } + +void ItemStore::itemUpdateSlot(ItemData data) +{ + qDebug()<<__func__; + for(std::shared_ptr& item: items_) + { + if(*item == data) + itemUpdated(std::weak_ptr(item)); + } +} + +std::shared_ptr ItemStore::getItem(uint32_t id) +{ + for(std::shared_ptr& item : items_) + { + if(item->id() == id) + return item; + } + return nullptr; +} + +void ItemStore::registerItemSource(ItemSource* source) +{ + qDebug()<<__func__<& item : items_) + itemDeleted(*item); + items_.clear(); + sigRefresh(); +} + +ItemStore globalItems; + diff --git a/src/items/itemstore.h b/src/items/itemstore.h index 4ee9651..437c4cc 100644 --- a/src/items/itemstore.h +++ b/src/items/itemstore.h @@ -2,7 +2,7 @@ #include #include #include "item.h" -#include "src/sensors/sensor.h" +#include "itemsource.h" #include @@ -10,7 +10,7 @@ class ItemStore: public QObject { Q_OBJECT private: - std::vector< std::shared_ptr > items_; + std::vector > items_; public: @@ -22,6 +22,9 @@ public: return &items_; } + std::shared_ptr getItem(uint32_t id); + + void registerItemSource(ItemSource* source); void store(QJsonObject &json); void load(const QJsonObject &json); @@ -31,11 +34,20 @@ signals: void itemDeleted(ItemData item); void itemAdded(std::weak_ptr Item); + void itemUpdated(std::weak_ptr Item); + void sigRefresh(); public slots: void removeItem(const ItemData& item); - void addItem(std::shared_ptr item); - void addItems(const std::vector>& itemsIn); - void itemStateChanged(const ItemData& item); + void addItem(std::shared_ptr item, bool inform = true); + void addItems(const std::vector>& itemsIn, bool inform = true); + void updateItems(std::vector items, bool inform = true); + void updateItem(const ItemData& item, bool inform = true); + void refresh(); + +private slots: + void itemUpdateSlot(ItemData data); }; + +extern ItemStore globalItems; diff --git a/src/items/messageitem.cpp b/src/items/messageitem.cpp index 0f51c53..32f9d5e 100644 --- a/src/items/messageitem.cpp +++ b/src/items/messageitem.cpp @@ -20,9 +20,8 @@ MessageItem::~MessageItem() closeMessageBox(); } -void MessageItem::setValue(uint8_t value) +void MessageItem::enactValue(uint8_t value) { - Item::setValue(value); if(value && !messageBox_) { if(!alertSoundFileName.isEmpty()) diff --git a/src/items/messageitem.h b/src/items/messageitem.h index 8b503c1..d23fb11 100644 --- a/src/items/messageitem.h +++ b/src/items/messageitem.h @@ -17,12 +17,10 @@ private: QSoundEffect alertSound; private slots: - void closeMessageBox(); -public: - - virtual void setValue(uint8_t value); +protected: + virtual void enactValue(uint8_t value) override; public: @@ -36,8 +34,8 @@ public: void setAlert(const QString& in); QString getAlert(); - virtual void store(QJsonObject& json); - virtual void load(const QJsonObject& json, const bool preserve = false); + virtual void store(QJsonObject& json) override; + virtual void load(const QJsonObject& json, const bool preserve = false) override; }; #endif // MESSAGEITEM_H diff --git a/src/items/poweritem.cpp b/src/items/poweritem.cpp index 998e6d2..cea1470 100644 --- a/src/items/poweritem.cpp +++ b/src/items/poweritem.cpp @@ -7,15 +7,14 @@ PowerItem::PowerItem(uint32_t itemIdIn, QString name, uint8_t value, QObject* p parent) { stateChanged(Sensor(Sensor::TYPE_SHUTDOWN_IMMINENT, 0, 0, "Shutdown Imminent", true)); - setValue(true); + PowerItem::setValue(true); } -void PowerItem::setValue(uint8_t value) +void PowerItem::enactValue(uint8_t value) { - qDebug()<<"shutdown"; - Item::setValue(value); if(!value) { + qDebug()<<"shutdown"; QTimer::singleShot(5000, this, &PowerItem::timeout); stateChanged(Sensor(Sensor::TYPE_SHUTDOWN_IMMINENT, 0, 1, "Shutdown Imminent", true)); } diff --git a/src/items/poweritem.h b/src/items/poweritem.h index ff1f263..76dea5e 100644 --- a/src/items/poweritem.h +++ b/src/items/poweritem.h @@ -16,12 +16,10 @@ signals: void stateChanged(Sensor sensor); private slots: - void timeout(); -public slots: - - virtual void setValue(uint8_t value); +protected: + virtual void enactValue(uint8_t value) override; public: PowerItem(uint32_t itemIdIn = QRandomGenerator::global()->generate(), QString name = "", uint8_t value = 0, @@ -30,5 +28,5 @@ public: { stateChanged(Sensor(Sensor::TYPE_SHUTDOWN_IMMINENT, 0, 0, "Shutdown Imminent", true)); } - virtual void store(QJsonObject& json); + virtual void store(QJsonObject& json) override; }; diff --git a/src/items/relay.cpp b/src/items/relay.cpp index 67197e0..e0a3d30 100644 --- a/src/items/relay.cpp +++ b/src/items/relay.cpp @@ -12,13 +12,14 @@ Relay::Relay(uint8_t id, QString name, uint16_t address, bool state, QObject* pa qDebug()<<"Relay "<relayOn(id_); - else micro_->relayOff(id_); + if(value) + micro_->relayOn(id_); + else + micro_->relayOff(id_); } } diff --git a/src/items/relay.h b/src/items/relay.h index f0ae640..8a35e98 100644 --- a/src/items/relay.h +++ b/src/items/relay.h @@ -18,9 +18,10 @@ private: uint8_t id_; uint16_t address_; -public slots: +protected: + virtual void enactValue(uint8_t value) override; - virtual void setValue(uint8_t value); +public slots: void on(); void off(); void toggle(); @@ -37,7 +38,7 @@ public: micro_ = micro; } - virtual void store(QJsonObject& json); - virtual void load(const QJsonObject& json, const bool preserve = false); + virtual void store(QJsonObject& json) override; + virtual void load(const QJsonObject& json, const bool preserve = false) override; }; #endif // RELAY_H diff --git a/src/items/rgbitem.cpp b/src/items/rgbitem.cpp index 46bc80d..cd47c7b 100644 --- a/src/items/rgbitem.cpp +++ b/src/items/rgbitem.cpp @@ -6,9 +6,8 @@ RgbItem::RgbItem(Microcontroller* micro, uint32_t itemIdIn, QString name, uint8 } -void RgbItem::setValue(uint8_t value) +void RgbItem::enactValue(uint8_t value) { - Item::setValue(value); value ? micro_->rgbOn() : micro_->rgbOff(); } diff --git a/src/items/rgbitem.h b/src/items/rgbitem.h index a503406..6e2a923 100644 --- a/src/items/rgbitem.h +++ b/src/items/rgbitem.h @@ -9,13 +9,12 @@ class RgbItem: public Item private: Microcontroller* micro_; -public slots: - - virtual void setValue(uint8_t value); +protected: + virtual void enactValue(uint8_t value) override; public: RgbItem(Microcontroller* micro, uint32_t itemIdIn = QRandomGenerator::global()->generate(), QString name = "", uint8_t value = 0, QObject* parent = nullptr); - virtual void store(QJsonObject& json); + virtual void store(QJsonObject& json) override; }; diff --git a/src/items/systemitem.cpp b/src/items/systemitem.cpp index c11ee29..7887ce5 100644 --- a/src/items/systemitem.cpp +++ b/src/items/systemitem.cpp @@ -1,7 +1,7 @@ #include "systemitem.h" #include -void SystemItem::setValue(uint8_t value) +void SystemItem::enactValue(uint8_t value) { QProcess::execute(value ? onCommand_ : offCommand_); } diff --git a/src/items/systemitem.h b/src/items/systemitem.h index 778780a..392e914 100644 --- a/src/items/systemitem.h +++ b/src/items/systemitem.h @@ -7,16 +7,13 @@ class SystemItem : public Item { Q_OBJECT private: - QString onCommand_; QString offCommand_; -public: - - virtual void setValue(uint8_t value); +protected: + virtual void enactValue(uint8_t value) override; public: - SystemItem(uint32_t itemIdIn = QRandomGenerator::global()->generate(), QString name = "Item", uint8_t value = 0, QObject *parent = nullptr); SystemItem(const ItemData& itemData, QObject *parent = nullptr); @@ -33,8 +30,8 @@ public: return offCommand_; } - virtual void store(QJsonObject& json); - virtual void load(const QJsonObject& json, const bool preserve = false); + virtual void store(QJsonObject& json) override; + virtual void load(const QJsonObject& json, const bool preserve = false) override; }; #endif // SYSTEMITEM_H diff --git a/src/main.cpp b/src/main.cpp index 529202d..f94ff78 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,26 +1,64 @@ #include -#include #include #include #include - -//Currently pipewire support is disabled -//#include - - -#ifndef Q_OS_ANDROID +#include #include #include #include -#endif -#include "microcontroller.h" #include "ui/mainwindow.h" #include "items/itemstore.h" #include "mainobject.h" +#include "programmode.h" -#define BAUD QSerialPort::Baud38400 +QJsonObject getJsonObjectFromDisk(const QString& filePath, bool* error = nullptr) +{ + QFile file; + file.setFileName(filePath); + + bool ret = file.open(QIODevice::ReadOnly); + if(!file.isOpen() || !ret) + { + std::cerr<<"Can not open config file: "<connectToHost(host, port, QIODevice::ReadWrite); - if(!microSocket->waitForConnected(1000)) + QIODevice* microDevice = nullptr; + if(tcpMicro) { - std::cout<<"Can not connect to to Server.\n"; - QMessageBox::critical(nullptr, "Error", "Can not connect to to Server"); - return 1; + int port = json["MicroTcpPort"].toInt(6856); + json["MicroTcpPort"] = port; + QString host = json["MicroTcpHost"].toString("127.0.0.1"); + json["MicroTcpHost"] = host; + + QTcpSocket* microSocket = new QTcpSocket; + + qInfo()<<"connecting to "<connectToHost(host, port, QIODevice::ReadWrite); + + if(!microSocket->waitForConnected(1000)) + { + qCritical()<<"Can not connect to tcp micro"; + storeJsonObjectToDisk(json, parser.value(settingsPathOption)); + if(programMode == PROGRAM_MODE_PRIMARY) + QMessageBox::critical(nullptr, "Error", "Can not connect to tcp micro"); + return 1; + } + microDevice = microSocket; } - masterIODevice = microSocket; + else + { + QString port = json["MicroSerialPort"].toString("ttyUSB0"); + json["MicroSerialPort"] = port; + int baud = json["MicroSerialBaud"].toInt(38400); + json["MicroSerialBaud"] = baud; + + QSerialPort *microPort = new QSerialPort; + microPort->setPortName(port); + microPort->setBaudRate(baud); + microPort->open(QIODevice::ReadWrite); + + if(!microPort->isOpen()) + { + qCritical()<<"Can not open serial port"< item){globalItems.addItem(item, false);}); + w->show(); + } + retVal = a.exec(); + + delete w; + delete microDevice; + mainObject.store(json); + storeJsonObjectToDisk(json, parser.value(settingsPathOption)); } else { - QSerialPort* microPort = new QSerialPort; - if(parser.isSet(portOption)) microPort->setPortName(parser.value(portOption)); - else microPort->setPortName("ttyUSB0"); + SecondaryMainObject mainObject(parser.value(hostOption), parser.value(portOption).toInt()); + MainWindow w(&mainObject); + //QObject::connect(&w, &MainWindow::sigSave, &mainObject, &MainObject::sendJson); + w.show(); - if(parser.isSet(portOption)) microPort->setBaudRate(parser.value(baudOption).toInt()); - else microPort->setBaudRate(BAUD); - - if(!microPort->open(QIODevice::ReadWrite)) std::cout<<"Can not open serial port "<portName().toStdString() - <<". Continueing in demo mode"<<'\n'; - masterIODevice = microPort; + retVal = a.exec(); } - MainObject mainObject(masterIODevice, parser.isSet(settingsPathOption) ? parser.value(settingsPathOption) : "", - !parser.isSet(secondaryOption)); - -#else - QTcpSocket* microSocket = new QTcpSocket; - microSocket->connectToHost("10.0.0.1", 6856, QIODevice::ReadWrite); - if(!microSocket->waitForConnected(1000)) - { - std::cout<<"Can not connect to to Server.\n"; - return 1; - } - masterIODevice = microSocket; - - MainObject mainObject(masterIODevice, parser.isSet(settingsPathOption) ? parser.value(settingsPathOption) : "", - !parser.isSet(secondaryOption)); -#endif - - - //mainwindow - MainWindow w(&mainObject); - QObject::connect(&mainObject.micro, SIGNAL(textRecived(QString)), &w, SLOT(changeHeaderLableText(QString))); - QObject::connect(&w, &MainWindow::sigBrodcast, &mainObject, &MainObject::sendJson); - QObject::connect(&w, &MainWindow::sigSave, &mainObject, &MainObject::storeToDisk); - QObject::connect(&w, &MainWindow::createdItem, &mainObject.items, &ItemStore::addItem); - if(!mainObject.micro.connected()) - w.changeHeaderLableText("No io debug only!"); - - w.show(); - - int retVal = a.exec(); - - if(masterIODevice) - delete masterIODevice; return retVal; } diff --git a/src/mainobject.cpp b/src/mainobject.cpp index d474d87..d92e0ae 100644 --- a/src/mainobject.cpp +++ b/src/mainobject.cpp @@ -1,179 +1,94 @@ #include "mainobject.h" -#include "items/messageitem.h" -MainObject::MainObject(QIODevice* ioDevice, const QString& settingsPathIn, const bool masterIn, QObject *parent) : - QObject(parent), - master(masterIn), - masterIODevice(ioDevice), - ioMultiplexer(masterIODevice), - micro(ioMultiplexer.getIoDevice()), - broadCast(ioMultiplexer.getIoDevice(), masterIn), - settingsPath(settingsPathIn), - sunSensorSource(49.884450, 8.650536), - powerItem(new PowerItem), - rgbItem(new RgbItem(µ, 5487422, "Rgb Lights")), - auxItem(new AuxItem(µ, 5487421, "Desk Light")) +#include +#include +#include +#include "items/itemstore.h" + +MainObject::MainObject(QObject *parent) : + QObject(parent) { - qDebug()<<"Is master:"<emmitSensor(); - items.addItem(rgbItem); - items.addItem(auxItem); - MessageItem::broadCast = &broadCast; - - Relay::setMicrocontroller(µ); - - connect(&broadCast, &BroadCast::gotJson, this, &MainObject::recivedJson); - QObject::connect(&broadCast, &BroadCast::gotSensorState, &globalSensors, &SensorStore::sensorGotState); - if(master) - connect(&broadCast, &BroadCast::jsonRequested, this, &MainObject::sendJson); - - if(master) - { - load(getJsonObjectFromDisk(settingsPath, &noSave)); - } - else - { - broadCast.requestJson(); - broadCast.requestSensors(); - } - -#ifndef Q_OS_ANDROID - Item::secondaryFlag = !master; -#endif } MainObject::~MainObject() { } -void MainObject::store(QJsonObject &json) +void MainObject::refresh() { - items.store(json); - - QJsonObject powerObject; - powerItem->store(powerObject); - json.insert("Power", powerObject); - QJsonDocument pwrDoc(powerObject); - - QJsonObject ocupancyObject; - ocupancySensor.store(ocupancyObject); - json.insert("Ocupancy", ocupancyObject); + globalItems.refresh(); } -void MainObject::load(const QJsonObject& json) +PrimaryMainObject::PrimaryMainObject(QIODevice* microDevice, QJsonObject* settings, QString host, int port, QObject *parent) : + MainObject(parent), + settings(settings), + microDevice(microDevice), + ioMultiplexer(microDevice), + micro(microDevice), + tcpServer(new TcpServer), + sunSensorSource(49.824972, 8.702194), + powerItem(new PowerItem), + rgbItem(new RgbItem(µ, 5487422, "Rgb Lights")), + auxItem(new AuxItem(µ, 5487421, "Desk Light")) { - items.clear(); + //connect sensors subsystem + connect(&globalSensors, &SensorStore::sensorChangedState, tcpServer, &TcpServer::sensorEvent); + connect(tcpServer, &TcpServer::gotSensor, &globalSensors, &SensorStore::sensorGotState); + connect(&sunSensorSource, &SunSensorSource::stateChanged, &globalSensors, &SensorStore::sensorGotState); + connect(µ, &Microcontroller::gotSensorState, &globalSensors, &SensorStore::sensorGotState); + + globalItems.registerItemSource(tcpServer); + globalItems.registerItemSource(µ); + + load(*settings); + + tcpServer->launch(QHostAddress(host), port); +} + +PrimaryMainObject::~PrimaryMainObject() +{ + store(*settings); +} + +void PrimaryMainObject::store(QJsonObject &json) +{ + globalItems.store(json); +} + +void PrimaryMainObject::load(const QJsonObject& json) +{ + globalItems.clear(); rgbItem->removeAllActors(); auxItem->removeAllActors(); powerItem->removeAllActors(); - items.addItem(rgbItem); - items.addItem(auxItem); - items.load(json); - powerItem->load(json["Power"].toObject()); - ocupancySensor.load(json["Ocupancy"].toObject()); - qDebug()<<"aray size: "<= 2) { rgbItem->load(json["Items"].toArray()[0].toObject()); auxItem->load(json["Items"].toArray()[1].toObject()); } - micro.requestState(); + globalItems.refresh(); } -void MainObject::storeToDisk() +SecondaryMainObject::SecondaryMainObject(QString host, int port, QObject *parent) : + MainObject(parent), + tcpClient(new TcpClient) { - if(master && !noSave) + connect(tcpClient, &TcpClient::gotSensor, &globalSensors, &SensorStore::sensorGotState); + globalItems.registerItemSource(tcpClient); + + if(!tcpClient->launch(QHostAddress(host), port)) { - QJsonObject json; - store(json); - storeJsonObjectToDisk(json, settingsPath); + QMessageBox::critical(nullptr, "Error", "Could not connect to "+host+":"+QString::number(port)); + exit(1); } } -void MainObject::recivedJson(const QJsonObject json) +SecondaryMainObject::~SecondaryMainObject() { - if(master && !noSave) - storeJsonObjectToDisk(json, settingsPath); - load(json); -} - -void MainObject::sendJson() -{ - QJsonObject json; - store(json); - broadCast.sendJson(json); -} - -QJsonObject MainObject::getJsonObjectFromDisk(const QString& filePath, bool* error) -{ - QFile file; - -#ifndef Q_OS_ANDROID - if(filePath.size() > 0) file.setFileName(filePath); - else -#endif - { - file.setFileName(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/shinterface.json"); - } - - file.open(QIODevice::ReadOnly); - if(!file.isOpen()) std::cerr<<"Can not open config file: "< -#include #include #include #include @@ -12,80 +11,66 @@ #include #include - -#ifndef Q_OS_ANDROID -#include -#include -#include -#endif - -#include "actors/alarmtime.h" #include "microcontroller.h" #include "ui/mainwindow.h" -#include "sensors/speakersensor.h" #include "sensors/sunsensor.h" -#include "sensors/ocupancysensor.h" -#include "sensors/sensor.h" -#include "items/itemstore.h" #include "items/auxitem.h" #include "items/rgbitem.h" #include "items/poweritem.h" #include "iomuliplexer.h" #include "broadcast.h" -//#include "pipewire.h" +#include "tcpserver.h" class MainObject : public QObject +{ + Q_OBJECT + +public: + explicit MainObject(QObject *parent = nullptr); + ~MainObject(); + +public slots: + void refresh(); +}; + +class PrimaryMainObject : public MainObject { Q_OBJECT public: + QJsonObject* settings; + //io - const bool master; - - bool noSave = false; - - QIODevice * const masterIODevice = nullptr; + QIODevice * const microDevice = nullptr; IoMuliplexer ioMultiplexer; Microcontroller micro; - BroadCast broadCast; - - - const QString settingsPath; + TcpServer* tcpServer; //sensors - SunSensorSource sunSensorSource; - OcupancySensorSource ocupancySensor; + SunSensorSource sunSensorSource; //items - ItemStore items; - std::shared_ptr powerItem; std::shared_ptr rgbItem; std::shared_ptr auxItem; - //PipeWireHandler pwHandler; +public: + explicit PrimaryMainObject(QIODevice* microDevice, QJsonObject* settings, QString host, int port, QObject *parent = nullptr); + ~PrimaryMainObject(); + void store(QJsonObject& json); + void load(const QJsonObject& json); +}; -private: - - static QJsonObject getJsonObjectFromDisk(const QString& filePath = "", bool* error = nullptr); - static bool storeJsonObjectToDisk(const QJsonObject& json, QString filePath = ""); +class SecondaryMainObject : public MainObject +{ + Q_OBJECT +public: + TcpClient* tcpClient; public: - explicit MainObject(QIODevice* ioDevice, const QString& settingsPathIn, const bool masterIn, QObject *parent = nullptr); - ~MainObject(); - - void store(QJsonObject& json); - - void load(const QJsonObject& json); - -signals: - -public slots: - - void storeToDisk(); - void sendJson(); - void recivedJson(const QJsonObject json); + explicit SecondaryMainObject(QString host, int port, QObject *parent = nullptr); + ~SecondaryMainObject(); }; diff --git a/src/microcontroller.cpp b/src/microcontroller.cpp index ba5f54b..174cfd0 100644 --- a/src/microcontroller.cpp +++ b/src/microcontroller.cpp @@ -3,8 +3,6 @@ #include #include -static constexpr bool debug = true; - void Microcontroller::relayToggle(int state, int relay) { char buffer[8]; @@ -40,7 +38,6 @@ void Microcontroller::changeRgbColor(const QColor color) char buffer[64]; int length = sprintf(buffer, "rgb set %03d %03d %03d\n", color.red(), color.green(), color.blue()); write(buffer, length); - std::cout<write(buffer); @@ -65,9 +59,6 @@ void Microcontroller::write(const QByteArray& buffer) void Microcontroller::write(char* buffer, const size_t length) { -#ifndef Q_OS_ANDROID - if constexpr(debug) std::cerr<write(buffer, length); @@ -95,7 +86,7 @@ bool Microcontroller::connected() else return false; } -void Microcontroller::requestState() +void Microcontroller::refresh() { write("state\n"); } @@ -147,12 +138,13 @@ void Microcontroller::processList(const QString& buffer) if(bufferList.size() >= 8 && buffer.startsWith("ITEM NUMBER:")) { relayList.push_back(processRelayLine(buffer)); + qDebug()<<"Micro item recived:"<getName(); } else if(buffer.contains("EOL")) { listMode = false; qDebug()<<"got relay list " << relayList.size(); - gotRelayList(relayList); + gotItems(relayList); relayList.clear(); } else listMode = false; @@ -160,7 +152,7 @@ void Microcontroller::processList(const QString& buffer) void Microcontroller::processRelayState(const QString& buffer) { - itemChanged(static_cast(*processRelayLine(buffer))); + updateItems({static_cast(*processRelayLine(buffer))}); } void Microcontroller::processSensorState(const QString& buffer) @@ -172,7 +164,11 @@ void Microcontroller::processSensorState(const QString& buffer) void Microcontroller::processMicroReturn() { - if(listMode) processList(_buffer); + qDebug()<<_buffer; + if(listMode) + { + processList(_buffer); + } else { if(_buffer.startsWith("Items:")) @@ -192,7 +188,9 @@ void Microcontroller::isReadyRead() while(_port->getChar(&charBuf)) { _buffer.push_back(charBuf); - if( _buffer.endsWith('\n') ) + + qDebug()<<_buffer; + if(_buffer.endsWith('\n') ) { _buffer.remove('\n'); processMicroReturn(); diff --git a/src/microcontroller.h b/src/microcontroller.h index 8392491..1845dc0 100644 --- a/src/microcontroller.h +++ b/src/microcontroller.h @@ -1,8 +1,6 @@ #ifndef MICROCONTROLLER_H #define MICROCONTROLLER_H -#include - #include #include #include @@ -17,8 +15,9 @@ #include "items/item.h" #include "items/relay.h" #include "sensors/sensor.h" +#include "items/itemsource.h" -class Microcontroller : public QObject +class Microcontroller : public ItemSource { Q_OBJECT @@ -65,7 +64,7 @@ public slots: void setPattern(int pattern); void startSunrise(); - void requestState(); + void refresh() override; void setAuxPwm(int duty); @@ -79,10 +78,6 @@ private slots: signals: void textRecived(const QString string); - void itemChanged(ItemData relay); - void auxStateChanged(int value); - void gotRelayList(std::vector< std::shared_ptr >&); - void gotSensorState(Sensor sensor); }; diff --git a/src/programmode.cpp b/src/programmode.cpp new file mode 100644 index 0000000..d37ba81 --- /dev/null +++ b/src/programmode.cpp @@ -0,0 +1,3 @@ +#include "programmode.h" + +program_mode_t programMode = PROGRAM_MODE_PRIMARY; diff --git a/src/programmode.h b/src/programmode.h new file mode 100644 index 0000000..ccbb900 --- /dev/null +++ b/src/programmode.h @@ -0,0 +1,13 @@ +#ifndef PROGRAMMODE_H +#define PROGRAMMODE_H + +typedef enum +{ + PROGRAM_MODE_PRIMARY = 0, + PROGRAM_MODE_HEADLESS_PRIMARY, + PROGRAM_MODE_UI_ONLY +} program_mode_t; + +extern program_mode_t programMode; + +#endif // PROGRAMMODE_H diff --git a/src/sensors/ocupancysensor.cpp b/src/sensors/ocupancysensor.cpp deleted file mode 100644 index 3bf7b7c..0000000 --- a/src/sensors/ocupancysensor.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "ocupancysensor.h" -#include -#include - -#include "../apgetconnected.h" - - -OcupancySensorSource::OcupancySensorSource(QObject *parent, const QString& device, - const QString& deviceMac): QObject (parent), deviceMac_(deviceMac), device_(device) -{ - QTimer::singleShot(timeoutMs, this, &OcupancySensorSource::Timeout); -} - -void OcupancySensorSource::sensorEvent(Sensor sensor) -{ - if(sensor.type == Sensor::TYPE_DOOR && sensor.id == 1 && sensor.field != 0.0f) - { - if(occupied == false) stateChanged(Sensor(Sensor::TYPE_OCUPANCY, 0, 1, "Occupancy")); - QTimer::singleShot(timeoutMs, this, &OcupancySensorSource::Timeout); - } -} - -void OcupancySensorSource::Timeout() -{ - int error = 0; - qDebug()<<"testing for occupancy"; - std::vector devices = ap::connectedDevices(device_.toLatin1().toStdString(), error); - if(error == 0) - { - bool found = false; - for(size_t i = 0; i < devices.size(); ++i) - { - std::string mac = ap::macAddrToString(devices[i]); - if(mac.find(deviceMac_.toLatin1().toStdString()) != std::string::npos) - { - found = true; - qDebug()<<"occupied"; - break; - } - } - stateChanged(Sensor(Sensor::TYPE_OCUPANCY, 0, found, "Occupancy")); - occupied = found; - } - else - { - stateChanged(Sensor(Sensor::TYPE_OCUPANCY, 0, true, "Occupancy")); - qDebug()<<"occupancy sensor error "< -#include -#include "sensor.h" - -class OcupancySensorSource : public QObject -{ - Q_OBJECT -private: - - QString deviceMac_; - QString device_; - bool occupied = true; - static constexpr unsigned timeoutMs = (15 * 60) * 1000; - -public: - explicit OcupancySensorSource(QObject *parent = nullptr, const QString& device = "wlan0", - const QString& deviceMac = "60:BE:B5:25:8C:E0"); - - void store(QJsonObject& json); - void load(const QJsonObject& json); - -public slots: - void sensorEvent(Sensor sensor); - -private slots: - - void Timeout(); - -signals: - void stateChanged(Sensor sensor); -}; diff --git a/src/sensors/pipewiresensor.cpp b/src/sensors/pipewiresensor.cpp deleted file mode 100644 index 89ee7e4..0000000 --- a/src/sensors/pipewiresensor.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "pipewiresensor.h" -#include - -static const struct pw_node_events node_events = { - .version = PW_VERSION_NODE_EVENTS, - .info = &PipeWireSensorSource::nodeEventHandler, - .param = nullptr -}; - -PipeWireSensorSource::PipeWireSensorSource(PipeWireHandler* handler, const std::string& nodeName, uint8_t id, QObject *parent) - : QObject{parent}, handler_(handler), nodeName_(nodeName), id_(id) -{ - connect(handler_, &PipeWireHandler::nodeAdded, this, &PipeWireSensorSource::nodeAdded); - connect(&timer, &QTimer::timeout, this, &PipeWireSensorSource::offTimeout); - timer.setSingleShot(true); -} - -void PipeWireSensorSource::offTimeout() -{ - if(state == false) - return; - state = false; - stateChanged(Sensor(Sensor::TYPE_AUDIO_OUTPUT, id_, state)); -} - -void PipeWireSensorSource::nodeEventHandler(void* data, const struct pw_node_info *info) -{ - PipeWireSensorSource* source = static_cast(data); - - if(info->state == source->prevState) - return; - - source->prevState = info->state; - - switch (info->state) - { - case PW_NODE_STATE_ERROR: - case PW_NODE_STATE_CREATING: - source->state = false; - source->stateChanged(Sensor(Sensor::TYPE_AUDIO_OUTPUT, source->id_, 0)); - break; - case PW_NODE_STATE_SUSPENDED: - case PW_NODE_STATE_IDLE: - if(source->state == true) - source->timer.start(10000); - break; - case PW_NODE_STATE_RUNNING: - if(source->state == false) - { - source->state = true; - source->stateChanged(Sensor(Sensor::TYPE_AUDIO_OUTPUT, source->id_, source->state)); - } - break; - default: - break; - } -} - -void PipeWireSensorSource::nodeAdded(PipeWireHandler::PwNode node) -{ - if(node.name == nodeName_) - { - - sinkNode = static_cast(pw_registry_bind(handler_->getRegistry(), node.id, PW_TYPE_INTERFACE_Node, PW_VERSION_CLIENT, 0)); - if(sinkNode) - { - qDebug()<<"Failed to register to required pipewire node"< -#include -#include -#include -#include - -#include "sensor.h" -#include "../pipewire.h" - -class PipeWireSensorSource : public QObject -{ - Q_OBJECT - - PipeWireHandler* handler_; - std::string nodeName_; - struct pw_node* sinkNode = nullptr; - struct spa_hook sinkListener; - pw_node_state prevState = PW_NODE_STATE_SUSPENDED; - QTimer timer; - uint8_t id_; - bool state = false; - -private slots: - void offTimeout(); - -public: - explicit PipeWireSensorSource(PipeWireHandler* handler, const std::string& nodeName, uint8_t id, QObject *parent = nullptr); - static void nodeEventHandler(void* data, const struct pw_node_info *info); - -signals: - void stateChanged(Sensor sensor); - -private slots: - void nodeAdded(PipeWireHandler::PwNode node); -}; - -#endif // PIPEWIRESENSOR_H diff --git a/src/sensors/sensor.h b/src/sensors/sensor.h index e64498e..80c37ab 100644 --- a/src/sensors/sensor.h +++ b/src/sensors/sensor.h @@ -4,6 +4,7 @@ #include #include #include +#include class Sensor { @@ -41,6 +42,15 @@ public: { lastSeen = QDateTime::currentDateTime(); } + Sensor(const QJsonObject& json) + { + type = json["SensorType"].toInt(0); + id = json["Id"].toInt(0); + field = json["Field"].toInt(0); + name = json["Name"].toString("Sensor"); + lastSeen = QDateTime::fromString(json["LastSeen"].toString("")); + hidden = json["Hidden"].toBool(false); + } inline bool operator==(const Sensor& in) const { return type==in.type && id == in.id; @@ -77,15 +87,32 @@ public: QString::number((type == Sensor::TYPE_HUMIDITY || type == Sensor::TYPE_TEMPERATURE) ? field*10 : field) + " TIME: " + QString::number(lastSeen.toSecsSinceEpoch()); } + inline void store(QJsonObject& json) + { + json["Type"] = "Sensor"; + json["SensorType"] = static_cast(type); + json["Id"] = static_cast(id); + json["Field"] = field; + json["Name"] = name; + json["LastSeen"] = lastSeen.toString(); + json["Hidden"] = hidden; + } inline void generateName() { - if(type == TYPE_TEMPERATURE) name = "Temperature " + QString::number(id); - else if(type == TYPE_DOOR) name = "Door " + QString::number(id); - else if(type == TYPE_BUTTON) name = "Button " + QString::number(id); - else if(type == TYPE_AUDIO_OUTPUT) name = "Speakers " + QString::number(id); - else if(type == TYPE_HUMIDITY) name = "Humidity " + QString::number(id); - else if(type == TYPE_SUN_ALTITUDE) name = "Solar Altitude"; - else if(type == TYPE_SHUTDOWN_IMMINENT) name = "Shutdown Imminent"; + if(type == TYPE_TEMPERATURE) + name = "Temperature " + QString::number(id); + else if(type == TYPE_DOOR) + name = "Door " + QString::number(id); + else if(type == TYPE_BUTTON) + name = "Button " + QString::number(id); + else if(type == TYPE_AUDIO_OUTPUT) + name = "Speakers " + QString::number(id); + else if(type == TYPE_HUMIDITY) + name = "Humidity " + QString::number(id); + else if(type == TYPE_SUN_ALTITUDE) + name = "Solar Altitude"; + else if(type == TYPE_SHUTDOWN_IMMINENT) + name = "Shutdown Imminent"; else name = "Sensor Type " + QString::number(type) + " Id " + QString::number(id); } }; diff --git a/src/sensors/speakersensor.cpp b/src/sensors/speakersensor.cpp deleted file mode 100644 index e2a4171..0000000 --- a/src/sensors/speakersensor.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "speakersensor.h" - -#include - -SpeakerSensorSource::SpeakerSensorSource(QString name, QObject *parent) : QObject(parent), name_(name) -{ - silenceCount = 0; -} - -SpeakerSensorSource::~SpeakerSensorSource() -{ - abort(); -} - -void SpeakerSensorSource::run() -{ - abort(); - arecord.start( "arecord", {"--disable-softvol", "-r", "8000", "-D", "front", "-"}); - - connect(&timer, SIGNAL(timeout()), this, SLOT(doTick())); - timer.setInterval(500); - timer.start(); - - stateChanged(Sensor(Sensor::TYPE_AUDIO_OUTPUT, 0, 1, name_)); -} - - -void SpeakerSensorSource::abort() -{ - if(arecord.state() == QProcess::Running)arecord.close(); - if(timer.isActive())timer.stop(); -} - -void SpeakerSensorSource::doTick() -{ - if(arecord.state() == QProcess::Running) - { - QByteArray buffer = arecord.readAllStandardOutput(); - //qDebug()<<(int16_t)buffer[0]; - for(long i = 0; i < buffer.size(); i++) - { - if((int16_t)buffer.at(i) != -128) - { - silenceCount = 0; - } - } - if(silenceCount > 40 && state) - { - stateChanged(Sensor(Sensor::TYPE_AUDIO_OUTPUT, 0, 0, name_)); - state = false; - } - else if(silenceCount == 0 && !state) - { - stateChanged(Sensor(Sensor::TYPE_AUDIO_OUTPUT, 0, 1, name_)); - state = true; - } - silenceCount++; - } -} diff --git a/src/sensors/speakersensor.h b/src/sensors/speakersensor.h deleted file mode 100644 index 8479ff2..0000000 --- a/src/sensors/speakersensor.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef AMPMANAGER_H -#define AMPMANAGER_H - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "sensor.h" - - -class SpeakerSensorSource : public QObject -{ - Q_OBJECT -private: - QString name_; - bool state = true; - QTimer timer; - -public: - explicit SpeakerSensorSource(QString name = "", QObject *parent = nullptr); - ~SpeakerSensorSource(); - -public slots: - void run(); - void abort(); - -signals: - void stateChanged(Sensor sensor); - -private slots: - void doTick(); - -private: - long silenceCount = 0; - - QProcess arecord; -}; - -#endif // AMPMANAGER_H diff --git a/src/tcpserver.cpp b/src/tcpserver.cpp new file mode 100644 index 0000000..b6f82e2 --- /dev/null +++ b/src/tcpserver.cpp @@ -0,0 +1,277 @@ +#include +#include +#include + +#include "items/item.h" +#include "items/itemstore.h" +#include "tcpserver.h" + + +TcpService::TcpService(QObject* parent): + ItemSource(parent) +{} + +QJsonObject TcpService::createMessage(const QString& type, const QJsonArray& data) +{ + QJsonObject json; + json["MesageType"] = type; + json["Data"] = data; + return json; +} + +void TcpService::sensorEvent(Sensor sensor) +{ + QJsonArray sensors; + QJsonObject sensorjson; + sensor.store(sensorjson); + sensors.append(sensorjson); + QJsonObject json = createMessage("SensorUpdate", sensors); + + sendJson(json); +} + +void TcpService::itemUpdated(std::weak_ptr item) +{ + QJsonArray items; + QJsonObject itemjson; + item.lock()->store(itemjson); + items.append(itemjson); + QJsonObject json = createMessage("ItemUpdate", items); + sendJson(json); +} + +void TcpService::refresh() +{ + sendJson(createMessage("GetSensors", QJsonArray())); + sendJson(createMessage("GetItems", QJsonArray())); +} + +void TcpService::sendSensors() +{ + QJsonArray sensors; + for(auto& sensor: *globalSensors.getSensors()) + { + QJsonObject sensorjson; + sensor.store(sensorjson); + sensors.append(sensorjson); + } + sendJson(createMessage("SensorUpdate", sensors)); +} + +void TcpService::sendItems() +{ + QJsonArray items; + for(auto& item: *globalItems.getItems()) + { + QJsonObject itemjson; + item->store(itemjson); + items.append(itemjson); + } + sendJson(createMessage("ItemUpdate", items)); +} + + +void TcpService::processIncomeingJson(const QByteArray& jsonbytes) +{ + qDebug()<<__func__<write(QString("MSG JSON LEN " + QString::number(jsonData.size()) + "\n").toLatin1() + jsonData); +} + +bool TcpClient::launch(const QHostAddress &address, quint16 port) +{ + socket->connectToHost(address, port); + return socket->waitForConnected(2000); +} + +void TcpClient::processIncomeingJson(const QByteArray& jsonbytes) +{ + QJsonDocument doc = QJsonDocument::fromJson(jsonbytes); + QJsonObject json = doc.object(); + QString type = json["MessageType"].toString(); + if(type == "ItemUpdate") + { + QJsonArray data = json["Data"].toArray(); + std::vector> items; + for(QJsonValueRef itemjson : data) + { + QJsonObject jsonobject = itemjson.toObject(); + std::shared_ptr item = Item::loadItem(jsonobject); + if(item) + items.push_back(item); + } + if(!items.empty()) + gotItems(items, true); + } + else + { + TcpService::processIncomeingJson(jsonbytes); + } +} + +TcpClient::~TcpClient() +{ + delete socket; +} + +TcpServer::TcpServer(QObject* parent): + TcpService(parent), + server(this) +{ +} + +void TcpServer::sendJson(const QJsonObject& json) +{ + for(auto client: clients) + { + QByteArray jsonData = QJsonDocument(json).toJson(); + client.socket->write(QString("MSG JSON LEN " + QString::number(jsonData.size()) + "\n").toLatin1() + jsonData); + } +} + +void TcpServer::processIncomeingJson(const QByteArray& jsonbytes) +{ + QJsonDocument doc = QJsonDocument::fromJson(jsonbytes); + QJsonObject json = doc.object(); + QString type = json["MessageType"].toString(); + if(type == "ItemUpdate") + { + QJsonArray data = json["Data"].toArray(); + std::vector> items; + for(QJsonValueRef itemjson : data) + { + QJsonObject jsonobject = itemjson.toObject(); + std::shared_ptr item = Item::loadItem(jsonobject); + if(item) + items.push_back(item); + } + if(!items.empty()) + gotItems(items, false); + } + else + { + TcpService::processIncomeingJson(jsonbytes); + } +} + +bool TcpServer::launch(const QHostAddress &address, quint16 port) +{ + return server.listen(address, port); +} + +void TcpServer::incomingConnection() +{ + while(server.hasPendingConnections()) + { + QTcpSocket* client = server.nextPendingConnection(); + if(client) + { + clients.push_back({client}); + connect(client, &QTcpSocket::errorOccurred, this, &TcpServer::socketError); + connect(client, &QTcpSocket::disconnected, this, &TcpServer::socketDisconnect); + connect(client, &QTcpSocket::readyRead, this, &TcpServer::socketReadyRead); + } + } +} + +void TcpServer::socketError(QAbstractSocket::SocketError socketError) +{ + (void)socketError; + for(size_t i = 0; i < clients.size(); i++) + { + if(clients[i].socket == TcpServer::sender()) + { + clients.erase(clients.begin()+i); + --i; + } + } +} +void TcpServer::socketDisconnect() +{ + for(size_t i = 0; i < clients.size(); i++) + { + if(clients[i].socket == TcpServer::sender()) + { + clients.erase(clients.begin()+i); + --i; + } + } +} + +void TcpServer::processComand(const QByteArray& command, Client& client) +{ + qDebug()<<__func__<readAll(); + bool remianing = true; + while(remianing) + { + remianing = false; + while(clients[i].state == STATE_IDLE && clients[i].buffer.contains('\n')) + { + size_t newlineIndex = clients[i].buffer.indexOf('\n'); + QByteArray command = clients[i].buffer.chopped(newlineIndex); + clients[i].buffer.chop(newlineIndex); + processComand(command, clients[i]); + remianing = true; + } + if(clients[i].state == STATE_RECV_JSON) + { + if(clients[i].recievebytes <= clients[i].buffer.size()) + { + QByteArray json = clients[i].buffer.chopped(clients[i].recievebytes); + clients[i].buffer.chop(clients[i].recievebytes); + clients[i].recievebytes = 0; + clients[i].state = STATE_IDLE; + processIncomeingJson(json); + remianing = true; + } + } + } + } + } +} + diff --git a/src/tcpserver.h b/src/tcpserver.h new file mode 100644 index 0000000..9c02556 --- /dev/null +++ b/src/tcpserver.h @@ -0,0 +1,89 @@ +#ifndef TCPSERVER_H +#define TCPSERVER_H + +#include +#include + +#include "sensors/sensor.h" +#include "items/item.h" +#include "items/itemsource.h" + +class TcpService : public ItemSource +{ + Q_OBJECT +signals: + void gotSensor(Sensor sensor); + +public slots: + void sensorEvent(Sensor sensor); + void itemUpdated(std::weak_ptr item); + virtual void refresh() override; + +public: + TcpService(QObject* parent = nullptr); + void sendSensors(); + void sendItems(); + virtual void sendJson(const QJsonObject& json) = 0; + virtual bool launch(const QHostAddress &address = QHostAddress::Any, quint16 port = 0) = 0; + +protected: + static QJsonObject createMessage(const QString& type, const QJsonArray& data); + virtual void processIncomeingJson(const QByteArray& jsonbytes); +}; + +class TcpClient : public TcpService +{ + Q_OBJECT + + QTcpSocket* socket; + +public: + TcpClient(QObject* parent = nullptr); + ~TcpClient(); + virtual bool launch(const QHostAddress &address = QHostAddress::Any, quint16 port = 0) override; + virtual void sendJson(const QJsonObject& json) override; + +protected: + virtual void processIncomeingJson(const QByteArray& jsonbytes) override; +}; + +class TcpServer : public TcpService +{ + Q_OBJECT + + typedef enum + { + STATE_IDLE, + STATE_RECV_JSON, + } client_state_t; + + struct Client + { + QTcpSocket* socket; + QByteArray buffer; + client_state_t state = STATE_IDLE; + long long recievebytes = 0; + }; + + std::vector clients; + QTcpServer server; + +public: + TcpServer(QObject* parent = nullptr); + virtual bool launch(const QHostAddress &address = QHostAddress::Any, quint16 port = 0) override; + virtual void sendJson(const QJsonObject& json) override; + +private slots: + void incomingConnection(); + void socketError(QAbstractSocket::SocketError socketError); + void socketDisconnect(); + void socketReadyRead(); + +protected: + virtual void processIncomeingJson(const QByteArray& jsonbytes) override; + +private: + void processComand(const QByteArray& command, Client& client); +}; + +#endif // TCPSERVER_H diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index b3e317e..fe02c56 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -9,38 +9,20 @@ MainWindow::MainWindow(MainObject * const mainObject, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), - colorChooser(this), - _micro(&mainObject->micro), - _powerItem(mainObject->powerItem) + colorChooser(this) { ui->setupUi(this); - - if(!mainObject->master) - { - connect(ui->pushButton_broadcast, &QPushButton::clicked, this, &MainWindow::sigBrodcast); - } - else - { - connect(ui->pushButton_broadcast, &QPushButton::clicked, this, &MainWindow::sigSave); - connect(ui->pushButton_broadcast, &QPushButton::clicked, this, &MainWindow::saved); - } + connect(ui->pushButton_broadcast, &QPushButton::clicked, this, &MainWindow::sigSave); + connect(ui->pushButton_broadcast, &QPushButton::clicked, this, [this](){QMessageBox::information(this, "Saved", "Settings where saved");}); connect(ui->pushButton_power, SIGNAL(clicked()), this, SLOT(showPowerItemDialog())); - //Relays - if(mainObject->master)connect(ui->pushButton_refesh, &QPushButton::clicked, _micro, &Microcontroller::requestState); - else - { - connect(ui->pushButton_refesh, &QPushButton::clicked, &mainObject->broadCast, &BroadCast::requestJson); - connect(ui->pushButton_refesh, &QPushButton::clicked, &mainObject->broadCast, &BroadCast::requestSensors); - } - connect(&mainObject->items, &ItemStore::itemAdded, ui->relayList, &ItemScrollBox::addItem); - connect(&mainObject->items, &ItemStore::itemDeleted, ui->relayList, &ItemScrollBox::removeItem); + connect(ui->pushButton_refesh, &QPushButton::clicked, mainObject, &MainObject::refresh); + connect(&globalItems, &ItemStore::itemAdded, ui->relayList, &ItemScrollBox::addItem); + connect(&globalItems, &ItemStore::itemDeleted, ui->relayList, &ItemScrollBox::removeItem); - for(size_t i = 0; i < mainObject->items.getItems()->size(); ++i) - { - ui->relayList->addItem(mainObject->items.getItems()->at(i)); - } + for(size_t i = 0; i < globalItems.getItems()->size(); ++i) + ui->relayList->addItem(globalItems.getItems()->at(i)); //Sensors ui->sensorListView->setShowHidden(false); @@ -53,7 +35,7 @@ MainWindow::MainWindow(MainObject * const mainObject, QWidget *parent) : connect(ui->button_color, SIGNAL(clicked()), &colorChooser, SLOT(show())); connect(ui->pushButton_addItem, &QPushButton::clicked, this, &MainWindow::showItemCreationDialog); - connect(ui->relayList, &ItemScrollBox::deleteRequest, &mainObject->items, &ItemStore::removeItem); + connect(ui->relayList, &ItemScrollBox::deleteRequest, &globalItems, &ItemStore::removeItem); ui->splitter->setStretchFactor(1, 1); } @@ -70,14 +52,10 @@ void MainWindow::showPowerItemDialog() diag.exec(); } -void MainWindow::saved() -{ - QMessageBox::information(this, "Saved", "Settings where saved"); -} - void MainWindow::slotChangedRgb(const QColor color) { - _micro->changeRgbColor(color); + (void)color; + //_micro->changeRgbColor(color); } void MainWindow::showItemCreationDialog() diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index e15c466..186b98d 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -5,13 +5,8 @@ #include #include #include -#include -#include "../actors/alarmtime.h" -#include "../microcontroller.h" -#include "../sensors/sensor.h" -#include "../items/itemstore.h" -#include "../items/poweritem.h" -#include "../broadcast.h" +#include +#include "src/items/poweritem.h" class MainObject; @@ -34,13 +29,10 @@ private: QColorDialog colorChooser; - Microcontroller *_micro; - std::shared_ptr _powerItem; signals: - void sigBrodcast(); void sigSave(); void createdItem(std::shared_ptr item); @@ -50,7 +42,6 @@ private slots: void slotChangedRgb(const QColor color); void showPowerItemDialog(); void showItemCreationDialog(); - void saved(); public slots: