Portál AbcLinuxu, 21. května 2024 19:58

plazmový mqtt čudliky na plochu

30.3.2021 00:41 | Přečteno: 5656× | Výběrový blog | poslední úprava: 31.3.2021 12:38

sem si začala psát mqtt widget pro plasma/kde5 desktopový prostředí protože žádnej hotovej mqtt widget tam neměli :O :/ eště to neni hotový ale ten stou rsm čtečkou sem taky strká nehotový :D ;D

POZOR!!!!!!!!!!!!!!!!!!!!!

momentálně to neni eště uplně vodladěný muže to udělat moc moc špatný věci jako zničit počítač smazat disk nebo popoužití widgetu když si vnoci špatně přikrijete nohy tak vás muže přijít stalman kousnout dopaty :O :O

 


plazmový čudliky


Update: konfigurační soubor se nemenuje 'config.xml' ale 'main.xml' :D

Plazma widgety na plochu kterým voni řikaj 'plasmoidy' se pišou hlavně v nějakejch divnejch qml skriptech který umožňujou používat javascript a c++ s knihovnama qt (tech qt takže to asi jako neni uplně svobodný :O :O vono qt nějak měnilo ty svý licence takže nikdo nasvěte neví který nástroje/knihovny sou svobodný který zdarma který zapeníze a který se nesměj používat vubec :O :O)

Tendleten čudlikovej widget má c++ backend kterej se do widgetu/plazmoidu dá strčit jako takovej jakože plugin. Na dělaní MQTT to používá cčkovou knihovnu paho vod eclipse hele. Maj tudletu knihovnu pro spousty jinejch jazyků i pro c++ ale ta vobyč cčková má v debianu bullseye rovnou balíček tak sem vzala tu ikdyž to asi jako neni správný c++kový řešení nějaký dělání s vobyč ukazatelama na funkce strukturama nebo polema/ukazatelama misto nějakejch těch jejich std::kontejnerů

jestli vás někoho jako napadlo proč sem nepoužila *.js knihovičku kterou tam eclipse taky má nóó tak vona boužel v qml nefunguje :O :/ qml umí nějaký jednoduchý websockety ale neštimuje to dosebe s touhletou knihovnou. Další možnost bylo vzit websockety a povidat si nima s nějakým vodděleným server skriptem jak to jako dělá třeba panon widget hele ale toje takový divný ne?? :O :O nóó takže sem to teda jakoby namastila v c++

Jak si jako udělat c++kovej plugin a registrovat qt/c++ třídu do qml sem vobšlehla tady u nějakýho pana kotelníka hele :D

adresářová struktura čudliků

Dohromady sou tam zatim jenom tři c++ třídy nastrkaný ve složce plugin. Singleton/jedináček toho našeho klienta pro dělání mqtt povidání v 'KlientProMQTT.h', třída co dělá jenom že přečte *.txt/*.json a strčí nám ho do qml (qml samo vosobě asi jako neumí číst soubory nadisku :O :O) v 'NacitadloSouboru.h' a pak 'PlasmoidPlugin.h' která dělá že nám ty dvě veci zaregistruje jako datový typy/oběty/elementy a mužem to pak v qml naimportovat jako knihovnu

Plazmoidy/kde widgety se musej skládat z nějaký složšky do který se dá soubor 'metadata.desktop' a do něj se napišou věci jako jak se ten widget/plazmoid bude menovat kde má skovanej hlavní skriptík 'main.qml' jakou má ikonku a takový věci. vtý složšce s 'metadata.desktop' si vyrobíme další složšku kterou pomenujem 'contents' a vní eště dvě další složsky, 'config' a 'ui'. Ve složšce 'config' si v souboru config.xml main.xml si podle návodu hele nadefinujem proměný jaký si widget/plazmoid umí pamatovat a v souboru config.qml umístění *.qml skriptíky jednotlivejch tabů v nastavování widgetu.

Ve složšce 'ui' musíme mit někde skovanej 'main.qml' skript kterej je hlavní součástka widgetu do kterýho si pak mužem importovat další voběkty/qml knihovny který mužou bejt skovaný taky v nějakejch svejch dalších složškách. plazmový čudliky maj všecky jednotlivý druhy čudliků v jedný složšce kde má každej druch svou 'třídu'. Je tam taková jakože společná třída 'Cudlik.qml' ze který vostatní čudliky 'děděj'.

Zatim to umí jenom sedum druhů čudliků:

složšková/adresářová struktura plazmovejch čudliků je takovádle zatim

.
├── CMakeLists.txt
├── package
│   ├── contents
│   │   ├── config
│   │   │   ├── config.qml
│   │   │   └── main.xml
│   │   └── ui
│   │       ├── cudliky
│   │       │   ├── Cudlik.qml
│   │       │   ├── Graf.qml
│   │       │   ├── Kruh.qml
│   │       │   ├── Moznosti.qml
│   │       │   ├── Napis.qml
│   │       │   ├── Prepinadlo.qml
│   │       │   ├── Soupatko.qml
│   │       │   └── Tlacitko.qml
│   │       ├── main.qml
│   │       └── NastavovaniCudliku.qml
│   └── metadata.desktop
└── plugin
    ├── CMakeLists.txt
    ├── KlientProMQTT.cpp
    ├── KlientProMQTT.h
    ├── NacitadloSouboru.cpp
    ├── NacitadloSouboru.h
    ├── PlasmoidPlugin.cpp
    ├── PlasmoidPlugin.h
    └── qmldir

instalace

má to různý závislosti. pro něco na nějakým novějším debianu s kde založeným doinstalujem všecko důležitý příkazem

sudo apt install cmake extra-cmake-modules libpaho-mqtt-dev qtdeclarative5-dev libkf5plasma-dev libssl-dev libcjson-dev

samotnej widget se kompiluje a instaluje tak že se vleze do tý složšky stim prvním CMakeLists.txt souborem a udělá se

cmake .
make
sudo make install

nóó a pak se to voběvuje mezi nainstalovanejma widgetama a mužem si to strčit naplochu ;D

pokuď si vtom uděláte nějaký změny kdyžuž máte widget puštěnej a přeinstalujete si ho tak pak jakoby musíte zavolat

plasmashell --replace

jinak tam zustane ten starej nezmeněnej

jak si jako nakonfigurovat čudliky

Konfiguruje se to načtením json kterým se naštelujou přihlašovací údaje barvičky a tak podobně

každej čudlik tam musí mit vyplněný atributy druh, název, xovou a ipsilonovou souřadnici v gridu/mřížšce, topic.

nepoviný atributy sou booly jestli muzePublikovat a muzePrijimat, QoS/kvalita služby, retain, jeCelociselny (má pochopytelně smysl jakoby jenom u čudliků co dělaj s číslama :D ;D), šířka a výška v počtu vobsazenejch chlívečků v tý mřížšce do který se budou čudliky strkat, jsonElement pro jakože hóódně primitivní parsování přijímanejch mqtt zpráviček v json formátu a další který mužete vidět v ukázkovým configu :D ;D

jestli chcete mit víc různejch widgetů protože vám nestačí jeden si musíte pohlídat aby měl jakoby každej jiný id!!!!!! :O :O jinak se budou navzájem vodpojovat :O :O

{
    "broker":
        {
            "adresa": "tcp://123.456.123.456:1883",
            "id": "widgetNaPlose",
            "uzivatel": "greta",
            "heslo": "1234"
        },
    "grid":
        {
            "sirka": 4,
            "vyska": 9
        },
    "barvy":
        {
            "pozadi": "#901a4314",
            "text": "#efe7bc",
            "aktivni": "#fad02c",
            "kontura": "#333652"
        },
    "cudliky": [
        {
            "druh": "Prepinadlo",
            "nazev": "Čudlík",
            "onHodnota": 1,
            "offHodnota": 0,
            "muzePublikovat": true,
            "muzePrijimat": true,
            "x": 0,
            "y": 0,
            "topic": "nejakej_topic/blablabla1",
            "retain": true,
            "QoS": 2
        },
        {
            "druh": "Prepinadlo",
            "nazev": "Druhej",
            "onHodnota": 1,
            "offHodnota": 0,
            "muzePublikovat": true,
            "muzePrijimat": true,
            "x": 1,
            "y": 0,
            "topic": "nejakej_topic/blablabla2",
            "retain": true,
            "QoS": 2
        },
        {
            "druh": "Prepinadlo",
            "nazev": "Třetí",
            "onHodnota": 1,
            "offHodnota": 0,
            "muzePublikovat": true,
            "muzePrijimat": true,
            "x": 2,
            "y": 0,
            "topic": "nejakej_topic/blablabla3",
            "retain": true,
            "QoS": 2
        },
        {
            "druh": "Prepinadlo",
            "nazev": "Čtvrtý",
            "onHodnota": 1,
            "offHodnota": 0,
            "muzePublikovat": true,
            "muzePrijimat": true,
            "x": 3,
            "y": 0,
            "topic": "nejakej_topic/blablabla4",
            "retain": true,
            "QoS": 2
        },
        {
            "druh": "Kruh",
            "nazev": "CO2 v atmosféře",
            "minHodnota": 123,
            "maxHodnota": 987,
            "muzePublikovat": true,
            "muzePrijimat": true,
            "x": 1,
            "y": 1,
            "sirka": 2,
            "vyska": 2,
            "topic": "nejakej_topic/x",
            "QoS": 0
        },
        {
            "druh": "Soupatko",
            "nazev": "Víkon vysavačů",
            "minHodnota": 0,
            "maxHodnota": 1000,
            "znakyZaHodnotou": "TW",
            "muzePublikovat": true,
            "muzePrijimat": true,
            "x": 0,
            "y": 1,
            "sirka": 1,
            "vyska": 1,
            "topic": "nejakej_topic/blah1",
            "QoS": 0
        },
        {
            "druh": "Soupatko",
            "nazev": "Víkon konvic",
            "minHodnota": 0,
            "maxHodnota": 1000,
            "znakyZaHodnotou": "TW",
            "muzePublikovat": true,
            "muzePrijimat": true,
            "x": 0,
            "y": 2,
            "topic": "nejakej_topic/blah2",
            "QoS": 0
        },
        {
            "druh": "Soupatko",
            "nazev": "Promořování",
            "minHodnota": 1234,
            "maxHodnota": 4321,
            "znakyZaHodnotou": " ☠",
            "muzePublikovat": true,
            "muzePrijimat": true,
            "x": 3,
            "y": 1,
            "topic": "nejakej_topic/promor",
            "QoS": 0
        },
        {
            "druh": "Kruh",
            "nazev": "Promořování",
            "minHodnota": 0,
            "maxHodnota": 4321,
            "znakyZaHodnotou": " ☠",
            "muzePublikovat": false,
            "muzePrijimat": true,
            "x": 3,
            "y": 2,
            "topic": "nejakej_topic/promor",
            "QoS": 0
        },

        {
            "druh": "Graf",
            "nazev": "Vysázenejch stromků vlese",
            "muzePublikovat": false,
            "muzePrijimat": true,
            "x": 0,
            "y": 4,
            "sirka": 4,
            "vyska": 2,
            "topic": "nejakej_topic/x",
            "jeCelociselny": false,
            "QoS": 0
        },
        {
            "druh": "Graf",
            "nazev": "Tloušťka ledovcový vrstvy",
            "muzePublikovat": false,
            "muzePrijimat": true,
            "x": 0,
            "y": 7,
            "sirka": 2,
            "vyska": 2,
            "topic": "nejakej_topic/x",
            "jeCelociselny": false,
            "QoS": 0
        },
        {
            "druh": "Napis",
            "nazev": "Kobaltová raketa zaměřená na:",
            "muzePublikovat": false,
            "muzePrijimat": true,
            "maOkraj": false,
            "x": 2,
            "y": 6,
            "sirka":2,
            "vyska": 2,
            "topic": "nejakej_topic/raketa"
        },
        {
            "druh": "Moznosti",
            "nazev": "vybrat cíl",
            "muzePublikovat": true,
            "muzePrijimat": true,
            "x": 2,
            "y": 8,
            "topic": "nejakej_topic/raketa",
            "seznamMoznosti": ["praha", "brno", "brusel"]
        },
        {
            "druh": "Tlacitko",
            "nazev": "Odpálení kobaltový rakety",
            "napis": "Odpálit!!!!",
            "coPosila": "bum!!!!!",
            "muzePublikovat": true,
            "muzePrijimat": false,
            "x": 3,
            "y": 8,
            "topic": "nejakej_topic/raketa"
        }
    ]
}

todo list

vodkazy na návody/tutoriály užitečný

https://zren.github.io/kde/docs/widget/

https://develop.kde.org/docs/plasma/widget/

https://techbase.kde.org/Development/Tutorials/Plasma5/QML2/GettingStarted

https://doc.qt.io/qt-5/qtquick-qmlmodule.html

https://api.kde.org/frameworks-api/frameworks-apidocs/frameworks/kquickcharts/html/index.html

https://develop.kde.org/docs/plasma/widget/configuration/

https://github.com/kotelnik/plasma-applet-weather-widget

zdrojáček

tady dole a taky tady hele

plugin/CMakeLists.txt

set(plasmoidplugin_SRCS
    PlasmoidPlugin.cpp
    KlientProMQTT.cpp
    NacitadloSouboru.cpp
    )
    

set(THREADS_PREFER_PTHREAD_FLAG ON)

find_package(Threads REQUIRED)
find_package(OpenSSL REQUIRED)

add_library(plasmoidplugin SHARED ${plasmoidplugin_SRCS})

target_compile_features(plasmoidplugin PRIVATE cxx_std_20)
target_compile_options(plasmoidplugin PRIVATE -fexceptions)

target_include_directories(plasmoidplugin PRIVATE ${OPENSSL_INCLUDE_DIR})

target_link_libraries(plasmoidplugin Qt5::Quick KF5::Plasma paho-mqtt3as cjson ${OPENSSL_LIBRARIES} Threads::Threads)

install(TARGETS plasmoidplugin DESTINATION ${QML_INSTALL_DIR}/org/kde/private/mqttCudliky)

install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kde/private/mqttCudliky)

plugin/KlientProMQTT.h

#ifndef KLIENT_PRO_MQTT_H
#define KLIENT_PRO_MQTT_H

#include <MQTTAsync.h>
#include <cjson/cJSON.h>

#include <string.h>
#include <unistd.h>

#include <string>
#include <map>

#include <qt5/QtCore/QDebug>
#include <qt5/QtCore/QObject>
#include <qt5/QtCore/QThread>
#include <qt5/QtCore/QString>
#include <qt5/QtQml/QJSEngine>
#include <qt5/QtQml/QQmlEngine>

#define CEKACI_CAS 10000L
#define VYCHOZI_QOS 0

//jakej je jako stav připojení  
enum StavPripojeni { CHYBA, NEPRIPOJENEJ, PRIPOJENEJ, ZAPSANEJ };

// podědíme z 
class KlientProMQTT : public QThread
{
    // qt oběkty to tady ve třídě musej mit :O :O
    Q_OBJECT
    
public:
    
    // jeto singleton/jedináček takže mužem mit jenom jednu instanci třídy vyrobenou
    // skovanou v nějaký statický proměný třídy
    // konstrukor je private a misto něj se volá nějaká statická metoda co vrací tu instanci společnou
    // singleton budem pak registrovat ve třídě 'PlasmoidPlugin' jako qml typ funckí 'qmlRegisterSingletonType'
    // ata chce aby metoda getInstance hamala tydlety ukazatele ;D
    static KlientProMQTT * ziskatInstanci(QQmlEngine * engine,  QJSEngine * scriptEngine);
    
    
    //void poslat(const QString & topic, const QString & zprava, unsigned int qos, bool retained);
    
    //StavPripojeni getStav() const {return stav;}

    // destruktor co dělá že uklidí
    ~KlientProMQTT();
    
signals:
    
    // signály který qt oběkt bude posílat
    // v qml nato sou napojený chytací metody
    // definujem jakoby jenom hlavičky metod žádný tělíčka. všecko co se do tý signal metody narve
    // se pak strčí do argumentu na stejný pozici vtěch qml/js funckí napojenejch
    
    // v c++/qt zdrojáčku se pak před nima musí psát 'Q_EMIT' abyto fungovalo :O :O
    
    // signály co dělaj že předaj klientem chycenou zprávu do qml frontendu
    void zpravaDoFrontendu(const QString & topic, const QString & obsahZpravy);
    void zpravaJsonDoFrontendu(const QString & topic, const QString & obsahZpravy);
    
    // signály který mqtt klient posílá když se vodpojí/připojí/něco se rozbije
    void odpojenej();
    void pripojenej();
    void chyba(QString textChyby = "chyba :D");
    
public Q_SLOTS:
    
    // funkce co připojujou a vodpojujou k/vod mqtt brokera
    // funkce připojit při úspěchu vrací true a při asi závažnějších chybách blije vyjímky
    bool pripojit();
    void odpojit();
    
    // nastaví atributy m_adresa m_id a tydlety všecky který potřebujem k připojování k brokeroj a vyrobí podle nich 
    // struktury m_connOpts, m_discOpts...... který budem nastrkávat do funckí z knihovničky MQTTAsync.h 
    void nastavit(const QString & adresa, const QString & id, const QString & uzivatel, const QString & heslo);
    
    // nastaví seznam topiců + jejich qos/kvalitu služby z qml/javascriptovejch polí strčenejch sem
    // každej topic by tam měl bejt jenom jednou napsanej
    // nemužem použít QMap nebo nějakej jinej víc chytřejší vobal protože naněco takovýho neumí qml převíst :O :/
    // převody mezi qml a qt/c++ maj popsaný tady hele https://doc.qt.io/qt-5/qtqml-cppintegration-data.html
    void nastavitSeznamTopicu(const std::vector<QString> & topicy, const std::vector<int> & qos);
    
    // pošlem z klienta zprávu
    // žere to jakoby ty qstringy ale ty sou převáděný na vobyč str::stringy uvnitř takže byse dotoho němeli strkat
    // žádný víc speciální znaky protože byje to asi jako nemuselo převíst :O :O
    // mqtt topicy by asi jako taky měli bejt složený jenom s vobyč ascii znáčků si myslim :O :O
    void poslat(const QString & topic, const QString & obsahZpravy, unsigned int qos = VYCHOZI_QOS, bool retained = false);
    
    // odpojí klienta nastaví adresu id etc + topicy/qos a zkusí znova udělat připojení
    void reset(const QString & adresa, const QString & id, const QString & uzivatel, const QString & heslo, const std::vector<QString> & topicy, const std::vector<int> & qos);
    
    // metoda na přešmiknutí vlákna
    // zavolá requestInterruption() a počká na ukončení 
    void stop();
    
    // metoda co řiká jestli je mqtt klient připojenej
    bool jePripojenej() const {return (bool)MQTTAsync_isConnected(m_klient);}
    
    // jestli vlákno běží
    bool bezi() const {return isRunning();}
    
private:
    
    // tajenj privátní konstruktor takže muže bejt zavolanej jenom z nějaký jiný metody týdletý třídy
    // singleton se nám vyrábí jenom  v metodě 'ziskatInstanci'
    explicit KlientProMQTT(QObject * parent = nullptr);
    
    // tady je skovaná ta jediná instance týdletý třídy
    static KlientProMQTT * instance;

    // metoda na zapsání k topicu 
    // před zapsáním nejdřiv musíme bejt připojený k brokeroj bezchybně
    void subscribe();
    
    // vypuštění vlákna
    // jenom se tam furt hlídá jestli je přiojenej/nepřipojenej
    // jedinej důvod proč misto vobyčejnýho qoběktu s callbackama je použitý vlákno jeto že když klient klient jednou ztratí spojení
    // a připojí se znova tak už to pak nechtělo dělat 'onConnect' callback takže nebylo možný z c++/qt říct qml/gui že neni připojenej
    // artelnativní řešení by asi jako mohlo bejt mit v main.qml nějakej časovač co by furt koukal jestli je klinet připojenej :O :O
    // možná tam jakoby maj voni nějakou chybku nevim :O :O
    void run() override;
    
    StavPripojeni stav;
    
    // přihlašovací údaje/data pro mqtt brokera
    std::string m_adresa;
    std::string m_id;
    std::string m_uzivatel;
    std::string m_heslo;
    
    // ke kolika topiců se chcem zapsat a seznam jejich názvů + QoS(kvalita služby)
    // mqtt vobyč cčková knihova chce vobyč starý cčkový pole/ukazate navstup
    size_t m_pocetTopicu;
    char ** m_nazvyTopicu;
    int * m_QoSsTopicu;
    
    // mqttasync.h knihovnou vyrobenej klient
    // s nim pracujou všecky ty funkce ztý knihovy
    MQTTAsync m_klient;
    
    // různý struktury nastavovací při připojování/vodpojování m_klienta
    // strkaj se do nich různý parametry + věčinou dvojice ukazatelů na funcke který sou pak
    // zavolaný jako callbacky potom cose to povede/nepovede udělat
    
    // připojovací
    MQTTAsync_connectOptions m_connOpts;
    
    // vodpojovací
    MQTTAsync_disconnectOptions m_discOpts;
    
    //na posílání zpráv
    MQTTAsync_responseOptions m_sendRespOpts;
    
    // subscribovací/na zapisování do topiců
    MQTTAsync_responseOptions m_subscribeRespOpts;
    
    // a tady sou ty různý callbacky jako statický metody
    // vobyčejný metody voběktu by to neumělo zhamat protože ty maj v c++ prej
    // jako takovej první neviditelnej argument ukazatel na sám sebe voběkt nebo takovýho něco
    // context je vodkaz na mqtt klienta připojenýho kterýho si musíme přetypovávat z void když ho třeba potřebujem
    
    // callback při vodpojení úspěch/neůspěch
    static void onDisconnect(void * context, MQTTAsync_successData * odpoved);
    static void onDisconnectFail(void * context, MQTTAsync_failureData * odpoved);
    
    // callbacky pro zapisování k topicům
    static void onSubscribe(void * context, MQTTAsync_successData * odpoved);
    static void onSubscribeFail(void * context, MQTTAsync_failureData * odpoved);
    
    // připojování
    // onConnect callbacky nejsou volaný při automatickým znovupřipojení klienta
    static void onConnect(void * context, MQTTAsync_successData * odpoved);
    static void onConnectFail(void * context, MQTTAsync_failureData * odpoved);
    
    // callbacky pro posílání zpráviček klientem
    static void onSend(void * context, MQTTAsync_successData * odpoved);
    static void onSendFail(void * context, MQTTAsync_failureData * odpoved);

    // při doručení zprávy
    static void onDeliver(void * context, MQTTAsync_token token);
    
    // ztráta spojení
    static void onConnLost(void * context, char * duvod);
    
    // při přijetí zprávy
    // pozor je tam hulvátstyle kontrola jestli je zpráva string/řetězec ve formátu json že
    // se kouká na první znak jestli toje složená závorka '{'
    static int onMessage(void * context, char * topicNazevStr, int topicStrZnaku, MQTTAsync_message * zprava);
    
    
};



#endif

plugin/KlientProMQTT.cpp

#include "KlientProMQTT.h"

using namespace std;

KlientProMQTT * KlientProMQTT::instance = nullptr;

KlientProMQTT * KlientProMQTT::ziskatInstanci(QQmlEngine * engine, QJSEngine * scriptEngine)
{
    Q_UNUSED(engine);
    Q_UNUSED(scriptEngine);
    
    if(KlientProMQTT::instance == nullptr)
    {
        KlientProMQTT::instance = new KlientProMQTT();
    }
    
    return KlientProMQTT::instance;
}

// konstrukotr skoro nic nedělá
// všecko bude nastavovaný jinejma metodama
KlientProMQTT::KlientProMQTT(QObject * parent) : QThread(parent), stav(NEPRIPOJENEJ), m_nazvyTopicu(nullptr), m_QoSsTopicu(nullptr)
{
}

// metoda stop poprosí vlákno vo to aby se jakože přešmiklo a počká
void KlientProMQTT::stop()
{
    requestInterruption();
    wait();
}


// run se zkusí připojit a pak furt vesmyčce kouká jestli neni znova připojenej
void KlientProMQTT::run()
{
    if(!pripojit())
    {
        qDebug()<<"nepovedlo se pripojit klienta";
        return;
    }
    while(!isInterruptionRequested())
    {

        usleep(CEKACI_CAS);
        
        if(stav == NEPRIPOJENEJ && jePripojenej())
        {
            stav = PRIPOJENEJ;
            Q_EMIT pripojenej();
        }
    }
    // když bylo vlákno přešmiknutý tak zkusíme vodpojit klienta
    // jestli je připojenej si metoda vodpojit hlídá sama
    odpojit();
    
    // qt::debugovací výstup
    qDebug()<<"mqtt client konci!!!!!!!!!";
}

// nastavování údajů na připojování k brokeroj
void KlientProMQTT::nastavit(const QString & adresa, const QString & id, const QString & uzivatel, const QString & heslo)
{
    // musíme převíst qstringy na vobyč std::stringy 
    // divný/neascii znkay se asi jako ztratěj tak pozor jako :O :O
    m_adresa = adresa.toStdString();
    m_id = id.toStdString();
    m_uzivatel = uzivatel.toStdString();
    m_heslo = heslo.toStdString();
    
    // inicianiluzujeme si ty struktury pro připojování/vodpojování/etc... výhozíma hodnotama
    m_connOpts = MQTTAsync_connectOptions_initializer;
    m_discOpts = MQTTAsync_disconnectOptions_initializer;
    m_sendRespOpts = MQTTAsync_responseOptions_initializer;
    m_subscribeRespOpts = MQTTAsync_responseOptions_initializer;
    
    // noa ty výhozí hodnoty jakože teťko přepišem nějakejma svejma kde potřebujem změnit
    
    // maximální možnej čas v sekundách kterej muže utýct vod posledního komunikování klienta s mqtt brokerem
    // když upline tak se pošle jakoby takovej 'ping' aby si navzájem řekli že sou voba eště naživu :O :O
    m_connOpts.keepAliveInterval = 20;
    
    // když máme zapnutý automatický znovupřipojování tak neni prej dobrý mit zapnutý promazávání session cache
    m_connOpts.cleansession = 0;
    
    //callbacky
    m_connOpts.onSuccess = KlientProMQTT::onConnect;
    m_connOpts.onFailure = KlientProMQTT::onConnectFail;
    
    // uživatel a heslo
    m_connOpts.username = m_uzivatel.c_str();
    m_connOpts.password = m_heslo.c_str();
    
    // zapnem automatický znovupřipojování a nastavíme znovupřipojovací interval ve kterým to jakoby tamto 
    // znovupřipojení zkouší třeba vod jedný do tří vteřin
    m_connOpts.automaticReconnect = 1;
    m_connOpts.minRetryInterval = 1;
    m_connOpts.maxRetryInterval = 3;
   
    // u vostatních struktur callbacky
    m_subscribeRespOpts.onSuccess = KlientProMQTT::onSubscribe;
    m_subscribeRespOpts.onFailure = KlientProMQTT::onSubscribeFail;
    
    m_sendRespOpts.onSuccess = KlientProMQTT::onSend;
    m_sendRespOpts.onFailure = KlientProMQTT::onSendFail;
    
    m_discOpts.onSuccess = KlientProMQTT::onDisconnect;
    m_discOpts.onFailure = KlientProMQTT::onDisconnectFail;
    
    // všecky tydlety struktury maj v sobě skovanej context/m_klienta
    // ho tam šoupnem až si ho v metodě připojit() vyrobíme ;D
}

// převedem vectory topiců/qos na ty ukazatelový pole. nejde to udělat nějak víc líp????? :O :O
// předpokádaj se stejně dlouhatánský pole aže se topicy nebudou vopakovat (to se hlídá v main.qml )
// neví někdo jestli de nějak v c++20 udělat todleto hele https://www.cplusplus.com/forum/general/228918/ :O :O :O :O
void KlientProMQTT::nastavitSeznamTopicu(const std::vector<QString> & topicy, const std::vector<int> & qos)
{
    if(topicy.size() != qos.size())
        throw runtime_error("neco je v qml moc spatne protoze do metody \'nastavitSeznamTopicu\' sou strceny vektory o ruzny dylce :O :O");

    if(topicy.size() == 0)
        qDebug()<<"do metody \'nastavitSeznamTopicu\' se strkaj vectory o nulovy dylce :O :O";
    
    
    if(m_nazvyTopicu != nullptr)
        delete [] m_nazvyTopicu;
    if(m_QoSsTopicu != nullptr)
        delete [] m_QoSsTopicu;
    
    m_pocetTopicu = topicy.size();
    m_nazvyTopicu = new char * [m_pocetTopicu];
    m_QoSsTopicu = new int [m_pocetTopicu];
    for(size_t i = 0; i < m_pocetTopicu; i++)
    {
        m_nazvyTopicu[i] = strdup(topicy[i].toStdString().c_str());
        m_QoSsTopicu[i] = qos[i];
        qDebug()<<"klient se bude chtit pripojovat k topicu \'"+QString(m_nazvyTopicu[i])+"\' s QoS == "<<m_QoSsTopicu[i];
    }
}


bool KlientProMQTT::pripojit()
{
    // návratovej chybvoej kód když se něco nepovede
    // mužem si pak dycky najít v hlavičkovým souboru 'MQTTAsync.h' tý paho knihovničky cože
    // to jako znamená tadleta chyba
    int rc; 
    
    // vyrobíme m_klienta 
    if ((rc = MQTTAsync_create(&m_klient, m_adresa.c_str(), m_id.c_str(), MQTTCLIENT_PERSISTENCE_NONE, nullptr))!= MQTTASYNC_SUCCESS)
    {
        string err = "nepodarilo se vyrobit MQTTAsync klienta!!!!!!!!!!!!\nnavratovej chybovej kod: ";
        err += to_string(rc);
        throw runtime_error(err);
    }

    if ((rc = MQTTAsync_setCallbacks(m_klient, m_klient, onConnLost, onMessage, onDeliver)) != MQTTASYNC_SUCCESS)
    {
        string err = "nepodarilo se klientoj nastavit callbacky!!!!!!!!!!!!\nnavratovej chybovej kod: ";
        err += to_string(rc);
        throw runtime_error(err);
    }
    
    // vyrobenýho klienta jakoby nastrkáme do těch nastavovacích struktur
    m_connOpts.context = m_klient;
    m_subscribeRespOpts.context = m_klient;
    m_sendRespOpts.context = m_klient;
    m_discOpts.context = m_klient;
    
    if((rc = MQTTAsync_connect(m_klient, &m_connOpts)) != MQTTASYNC_SUCCESS)
    {
        QString err = "nepodarilo se pripojit klienta!!!!!!!!!!!! navratovej chybovej kod: " + QString::number(rc);
        qDebug()<<err;
        Q_EMIT chyba("nepodarilo se pripojit klienta!!!!\nmrkni na prihlasovaci udaje");
        return false;
    }

    while(stav == NEPRIPOJENEJ)
        usleep(CEKACI_CAS);
    
    if(stav == CHYBA)
    {        
        QString err = "nepodarilo se subscribnout klienta!!!!!!";
        qDebug()<<err;
        Q_EMIT chyba(err);
        return false;
    }
    
    return true;
    
}

void KlientProMQTT::odpojit()
{
    // když neni připojenej tak ho nemužem začít vodpojovat
    // mqttasync.h nato nadává 
    if(!jePripojenej())
         return;
    int rc;
    if ((rc = MQTTAsync_disconnect(m_klient, &m_discOpts)) != MQTTASYNC_SUCCESS)
    {
        string err = "nepodarilo se zacit vodpojovani klienta!!!!!!!!!!!!\nnavratovej chybovej kod: " + to_string(rc);
        throw runtime_error(err);
    }
    // budem čekat než to jakoby nějak dopadne :D
    while (stav == PRIPOJENEJ && stav != CHYBA)
        usleep(CEKACI_CAS);
    
    // když to skončí chybou tak máme nějakej problémek kterej tady asi jako nevyřešíme
    if(stav == CHYBA)
    {        
        string err = "nepodarilo se vodpojit klienta!!!!!!!!!!!!";
        throw runtime_error(err);
    }
}

void KlientProMQTT::subscribe()
{
    if( stav != PRIPOJENEJ)
    {
        string err = "klient musi bejt pred subscribnutim pripojenej!!!!";
        throw runtime_error(err);
    }
    int rc;
    if ((rc = MQTTAsync_subscribeMany(m_klient, m_pocetTopicu, m_nazvyTopicu, m_QoSsTopicu, &m_subscribeRespOpts)) != MQTTASYNC_SUCCESS)
    {
        string err = "nepodarilo se zacit subscribovat klienta!!!!!!!!!!!!\nnavratovej chybovej kod: " + to_string(rc);
        throw runtime_error(err);
    }
}

void KlientProMQTT::poslat(const QString & topic, const QString & zprava, unsigned int qos, bool retained)
{
    // když neni klient připojenej nic se nebude posílat
    // posílání zpráviček z vodpojenýho klienta má jakoby zabránit zamikání čudliků v gui dycky když je klient vodpojenej
    if(!jePripojenej())
    {
        qDebug()<<"klient neni pripojenej takze se nic nebude posilat";
        return;
    }
    
    string zpravaStdstr = zprava.toStdString();
        
    MQTTAsync_message msg = MQTTAsync_message_initializer;
    msg.payload = (void *)zpravaStdstr.c_str();
    msg.payloadlen = zpravaStdstr.length();
    msg.qos = qos;
    msg.retained = int(retained);
        
    int rc;
    if ((rc = MQTTAsync_sendMessage(m_klient, topic.toStdString().c_str(), &msg, &m_sendRespOpts)) != MQTTASYNC_SUCCESS)
    {
        string err = "nepodarilo se poslat str zpravu!!!!!!!!!!!!\nnavratovej chybovej kod: " + to_string(rc);
        throw runtime_error(err);
    }
}

// vodpojíme nastavíme a zkusíme znova připojit
void KlientProMQTT::reset(const QString & adresa, const QString & id, const QString & uzivatel, const QString & heslo, const std::vector<QString> & topicy, const std::vector<int> & qos)
{
    odpojit();
    
    if(m_klient != nullptr)
        MQTTAsync_destroy(&m_klient);
    
    nastavit(adresa, id, uzivatel, heslo);
    nastavitSeznamTopicu(topicy, qos);
    
    stav = NEPRIPOJENEJ;
    pripojit();
}


//callbacky

void KlientProMQTT::onDisconnect(void * context, MQTTAsync_successData * odpoved)
{
    (void)context;
    (void)odpoved;
    instance->stav = NEPRIPOJENEJ;
    Q_EMIT instance->odpojenej();
    qDebug()<<"uspesne odpojeni"<<Qt::endl;
}
    
void KlientProMQTT::onDisconnectFail(void * context, MQTTAsync_failureData * odpoved)
{
    (void)context;
    instance->stav = CHYBA;
    Q_EMIT instance->chyba("neuspesne vodpojeni");
    qDebug()<<"neuspesne vodpojeni "<<Qt::endl<<"chybovy kod: "<<odpoved->code<<Qt::endl;
}
    
void KlientProMQTT::onSubscribe(void * context, MQTTAsync_successData * odpoved)
{
    (void)context;
    (void)odpoved;
    instance->stav = ZAPSANEJ;
    qDebug()<<"uspesne zapsani k topicu"<<Qt::endl;
}
    
void KlientProMQTT::onSubscribeFail(void * context, MQTTAsync_failureData * odpoved)
{
    (void)context;
    instance->stav = CHYBA;
    Q_EMIT instance->chyba("neuspesne zpasani k topicu");
    qDebug()<<"neuspesne zpasani k topicu"<<Qt::endl<<"chybovy kod: "<<odpoved->code<<Qt::endl;
}
    
void KlientProMQTT::onConnect(void * context, MQTTAsync_successData * odpoved)
{
    (void)context;
    (void)odpoved;
    qDebug()<<"uspesne pripojeno"<<Qt::endl;
    instance->stav = PRIPOJENEJ;
    Q_EMIT instance->pripojenej();
    instance->subscribe();
}
    
void KlientProMQTT::onConnectFail(void * context, MQTTAsync_failureData * odpoved)
{
    (void)context;
    qDebug()<<"neslo pripojit"<<Qt::endl<<"chybovy kod: "<<odpoved->code<<Qt::endl;
    instance->stav = CHYBA;
    Q_EMIT instance->chyba("neslo pripojit");
}
    
void KlientProMQTT::onSend(void * context, MQTTAsync_successData * odpoved)
{
    (void)context;
    (void)odpoved;
    qDebug()<<"poslalo se"<<Qt::endl;
}
    
void KlientProMQTT::onSendFail(void * context, MQTTAsync_failureData * odpoved)
{
    (void)context;
    qDebug()<<"nepodarilo se odeslat ZPRAVU"<<Qt::endl<<"chybovy kod: "<<odpoved->code<<Qt::endl;
    qDebug()<<"klient se tedko pokusi vodpojit";
    Q_EMIT instance->chyba("neslo poslat zpravu");
    instance->odpojit();
}

void KlientProMQTT::onDeliver(void * context, MQTTAsync_token token)
{
    (void)context;
    qDebug()<<"doruceni zpravy potvrzeno"<<Qt::endl<<"token: "<<token<<Qt::endl<<Qt::endl;
}
    
void KlientProMQTT::onConnLost(void * context, char * duvod)
{
    (void)context;
    instance->stav = NEPRIPOJENEJ;
    Q_EMIT instance->odpojenej();
    qDebug()<<"spojeni ztraceno";
    if(duvod != nullptr)
        qDebug()<<"duvod odpojeni: "<<duvod;
}
    
//vrací jedničku když zprávu správně přijmem jinak nám ji to zkusí znova strčit
int KlientProMQTT::onMessage(void * context, char * topicNazevStr, int topicStrZnaku, MQTTAsync_message * zprava)
{
    (void)context;
    (void)topicStrZnaku;
            
    if(zprava->payloadlen > 0)
    {
        qDebug()<<"prijata zprava do topicu \'" + QString(topicNazevStr) +"\' s vobsahem:";
        qDebug()<<QString::fromLocal8Bit((char *)zprava->payload);
        
        QString topicQstr = QString::fromLocal8Bit(topicNazevStr), zpravaQstr = QString::fromLocal8Bit((char *)zprava->payload);
                
        if( ((char *)zprava->payload)[0] == '{' )
        {
            cJSON * jsonZprava = cJSON_Parse((char*)zprava->payload);
            if (jsonZprava != nullptr)
            {
                //zprava asi jako bude ve formatu json
                cJSON_Delete(jsonZprava);
                        
                Q_EMIT instance->zpravaJsonDoFrontendu(topicQstr, zpravaQstr);
                        
                MQTTAsync_freeMessage(&zprava);
                MQTTAsync_free(topicNazevStr);
                return 1;
            }
        }
                
        Q_EMIT instance->zpravaDoFrontendu(topicQstr, zpravaQstr);
    }
    else
        qDebug()<<"prijata prazdna zprava :O :O";
            
    MQTTAsync_freeMessage(&zprava);
    MQTTAsync_free(topicNazevStr);
    return 1;
}
    
    
// destruktor co dělá že uklidí
KlientProMQTT::~KlientProMQTT()
{
    if(jePripojenej())
        odpojit();
    
    if(m_klient != nullptr)
        MQTTAsync_destroy(&m_klient);
    
    delete [] this->m_nazvyTopicu;
    delete [] this->m_QoSsTopicu;
}

plugin/NacitadloSouboru.h

#ifndef NACITADLO_SOUBORU_H
#define NACITADLO_SOUBORU_H

#include <qt5/QtCore/QObject>
#include <qt5/QtCore/QUrl>
#include <qt5/QtCore/QFile>
#include <qt5/QtCore/QDebug>

class NacitadloSouboru : public QObject
{
    Q_OBJECT
    
public:
    
    explicit NacitadloSouboru(QObject * parent = nullptr) : QObject(parent){}
    ~NacitadloSouboru(){}
    
    Q_SLOT QString nacistSoubor(const QUrl & cesta);
};


#endif

plugin/NacitadloSouboru.cpp

#include "NacitadloSouboru.h"

#include <stdio.h>
#include <stdlib.h>

QString NacitadloSouboru::nacistSoubor(const QUrl & cesta)
{    
        QFile soubor(cesta.toLocalFile());
        
        if(!soubor.open(QFile::ReadOnly | QFile::Text))
            return "neslo otevrit!!!!!!!!!!";
        else
            return soubor.readAll();
        
        
}

plugin/PlasmoidPlugin.h

#ifndef PLASMOIDPLUGIN_H
#define PLASMOIDPLUGIN_H

#include <QQmlExtensionPlugin>

class QQmlEngine;
class PlasmoidPlugin : public QQmlExtensionPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")

public:
    void registerTypes(const char *uri) override;
};

#endif // PLASMOIDPLUGIN_H

plugin/PlasmoidPlugin.cpp

#include "PlasmoidPlugin.h"
#include "KlientProMQTT.h"
#include "NacitadloSouboru.h"

#include <QtQml>
#include <QDebug>

void PlasmoidPlugin::registerTypes(const char *uri)
{
    Q_ASSERT(uri == QLatin1String("org.kde.private.mqttCudliky"));
    
    qmlRegisterSingletonType<KlientProMQTT>(uri, 1, 0, "Klient", KlientProMQTT::ziskatInstanci);
    qmlRegisterType<NacitadloSouboru>(uri, 1, 0, "Nacitadlo");
}

plugin/qmldir

module org.kde.private.mqttCudliky

plugin plasmoidplugin

package/metadata.desktop

[Desktop Entry]
Name=mqttCudliky
Comment=Nejvíc nejkrásnější mqtt widget

Type=Service
X-KDE-ParentApp=
X-KDE-PluginInfo-Author=gréta
X-KDE-PluginInfo-Email=gretulililinka@protonmail.com
X-KDE-PluginInfo-License=nevim jak to vomezuje licence qt :D
X-KDE-PluginInfo-Name=org.kde.mqttCudliky
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=www.replace.com
X-KDE-ServiceTypes=Plasma/Applet
X-Plasma-NotificationArea=true
X-Plasma-API=declarativeappletscript
X-Plasma-MainScript=ui/main.qml
X-Plasma-RemoteLocation=
X-KDE-PluginInfo-Category=Environment and Weather
Icon=preferences-system-network-sharing

package/contents/config/config.qml

//tady sou definovaný taby v konfiguraci widgetu naploše
import QtQuick 2.0

import org.kde.plasma.configuration 2.0 as PlasmaConfig

PlasmaConfig.ConfigModel
{
    PlasmaConfig.ConfigCategory
    {
        name: i18n('Nastavování čudliků')
        icon: 'preferences-desktop-plasma'
        source: 'NastavovaniCudliku.qml'
    }

}

 

package/contents/config/main.xml

<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
    <kcfgfile name=""/>

    <group name="General">
        <entry name="adresa" type="String">
            <default></default>
        </entry>
        <entry name="id" type="String">
            <default></default>
        </entry>
        <entry name="uzivatel" type="String">
            <default></default>
        </entry>
        <entry name="heslo" type="String">
            <default></default>
        </entry>
    </group>
    <group name="Cudliky">
        <entry name="konfiguracniJson" type="String">
            <default>

            </default>
        </entry>
    </group>
</kcfg>

package/contents/ui/main.qml

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.11

//import org.kde.quickcharts 1.0 as Charts
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.components 3.0 as PlasmaComponents

// naimportujem si všecky voběkty ze složšky 'cudliky'
import "./cudliky"

// taky si naimportujem náš c++/qt plugin
import org.kde.private.mqttCudliky 1.0

//chceme takovej ten velkej widget naplochu
Item
{
    // podporujem jenom velkej widget strčenej naplochu
    Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation
    
    Plasmoid.fullRepresentation: Item
    {
        id: main
        
        // minimální šířka/vejška widgetu pole počtu čudliků
        Layout.minimumWidth: (velikostMezer + 64) * main.sloupcu * PlasmaCore.Units.devicePixelRatio
        Layout.minimumHeight: (velikostMezer + 64) * main.radku * PlasmaCore.Units.devicePixelRatio
        
        // počet sloupců a řádků grid/mřížškovýho layoutu/rozložení čudliků
        // čudliky se budou strkat dotoho elmentu grid
        property alias radku: grid.rows
        property alias sloupcu: grid.columns
        
        // velikost mezer mezi čudlikama v pixelech
        property int velikostMezer: 2
        
        // různý pole který držej referenci na voběkty čudliků
        
        // uplně všecky čudliky
        property var vseckyCudliky: []
        
        // čudliky podle jednotlivejch topiců
        // key/klíč pole sou názvy topiců
        property var cudlikyPodleTopicu: []
        
        // taky čudliky podle topiců ale takový co dělaj že chtěj psaníčko v *.json formátu :D ;D
        property var jsonCudlikyPodleTopicu: []
        
        // seznam jenom těch čudliků co uměj publikovat
        // potřebujem znát nato abysme je mohli dycky všecky zamknout když mqtt klient ztratí spojení s brokerem
        property var publikovaciCudliky: []
        
        
        // 'sada' všech topiců s nejvíc nejvěčím QoS jako hodnotou
        // potřebujem ji mit jako vobyč array/pole abysme ji mohli strčit do qt/c++
        // v seznamTopicu by měli bejt jenom stringy a v qos zase samý int
        // ( de ňák v js hezky rozlousknout pole na dvě různý žeby v jednom byly keys a vdruhým values?????? nějakej takovej vopak zip :O :O )
        property var seznamTopicu: []
        property var seznamTopicuQoS: []
        
        // výchozí barvy když nejsou definovaný v konfigu
        property color barvaTextu: 'black'
        property color barvaAktivni: 'red'
        property color barvaKontury: 'green'
        property color barvaPozadi: 'white'
        
        // načtem ůdaje o brokeroj/přihlašovací ůdaje z konfigu
        // mužou bejt i undefined/nedefinovaný to se pak hlídá dál aby se nezačalo připojovat
        property string adresa: plasmoid.configuration.adresa
        property string id: plasmoid.configuration.id
        property string uzivatel: plasmoid.configuration.uzivatel
        property string heslo: plasmoid.configuration.heslo
        
        // výchozí konfigurační string pro případ že neni žádnej uloženej v konfigu
        
        // normálně by asi jako měla fungovat hodnota strčená mezi <default></default> tagy v 
        // main.xml ale ňák ji to nechtělo načítat :O :/
        // možná to neumí zhamat *.json možná dělaj problémy uvozovky možná to nefunguje
        // jenom v tom testovacím plasmoidviewer vokýnku. nevim :O :/
        
        property string jsonString: 
        '{

        "grid":
            {
                "sirka": 1,
                "vyska": 1
            },
        "barvy":
            {
                "pozadi": "#0f808080",
                "text": "#d3d3d3",
                "aktivni": "#00ffff",
                "kontura": "#191919"
            },
        "cudliky": [
            {
                "druh": "Moznosti",
                "nazev": "čudlík",
                "muzePublikovat": false,
                "muzePrijimat": false,
                "x": 0,
                "y": 0,
                "topic": "nejaky_topic",
                "seznamMoznosti": ["vychozi nastaveni cudliku"]
            }
            ]
        }'

        // funcke co dělá že veme json a podle něj vyrobí všecky čudliky
        // nastaví barvičky/velikost mřížšky a takový tydlety
        // taky nám naplní všecky ty pole čudliků
        function jsonNaElementy(json)
        {

            // nastavení počtu řádků/sloupců mřížšky
            main.sloupcu = json.grid.sirka;
            main.radku = json.grid.vyska;
            
            // jestli jsou v json barvičky tak nastavíme barvičky :D ;D
            if(json.hasOwnProperty('barvy'))
            {
                barvaAktivni = json.barvy.aktivni;
                barvaTextu = json.barvy.text;
                barvaPozadi = json.barvy.pozadi;
                barvaKontury = json.barvy.kontura;
            }
            
            // noa teďko projdem všecky čudliky v json a zkusíme je dynamicky vyrobit a nastrkat do tý mřížšky
            for(var i in json.cudliky)
            {
                // vezmem si z json další json samotnýho jednoho čudlika
                var cudlikJson = json.cudliky[i];
                
                // id našeho čudliku vyrobenýho
                // nějaký id asi musíme vyplnit jinak nemá nějakej víc věčí význam
                var id = 'cudlik_' + i;

                // čudlik budem vyrábět funkcí 'createQmlObject' která má navstupu string kterej vobsahuje zdrojáček qml elementu
                // náš string začnem importem
                var obektStr = 'import "./cudliky";';
                obektStr += cudlikJson.druh + '{';
                
                // jestli muže čudlik publikovat tak taky musí mit možnost posílat publikovací signál dalším qt/qml elementům
                // bude posílat signál s topicem a nějakou tamtou zprávou
                if(cudlikJson.muzePublikovat)
                {
                    obektStr += 'signal zpravaOdCudliku(string topic, string zprava);';
                }
                obektStr += '}';
                
                // vyrobíme si čudlik strčíme ho do gridu a nastavíme mu nějaký id
                var cudlik = Qt.createQmlObject(obektStr, grid, id);
                
                // další atributy čudliku nastavíme jako atributy javascriptovýho voběktu
                
                // méno a topic ke kterýmu je připojenej
                cudlik.nazev = cudlikJson.nazev;
                cudlik.mqttTopic = cudlikJson.topic;
                
                // čudlik bude v mřížšce vyplňovat všecky přidělený chlívečky
                cudlik.Layout.fillHeight = true;
                cudlik.Layout.fillWidth = true;
                
                // nastavíme pozici v mřížšce/gridu
                cudlik.Layout.column = cudlikJson.x;
                cudlik.Layout.row = cudlikJson.y;
                
                // jestli má čudlik v json nastavenou nějakou šířku/výšku teda jakože kolik
                // chlívečků mřížky má našířku/navejšku tak nastavíme
                if(cudlikJson.hasOwnProperty('sirka'))
                    cudlik.Layout.columnSpan = cudlikJson.sirka;
                if(cudlikJson.hasOwnProperty('vyska'))
                    cudlik.Layout.rowSpan = cudlikJson.vyska;
                
                // vobarvení čudliku
                // jinak má svý nějaký výchozí barvičky
                cudlik.barvaAktivni = barvaAktivni;
                cudlik.barvaTextu = barvaTextu;
                cudlik.barvaPozadi = barvaPozadi;
                cudlik.barvaKontury = barvaKontury;
                
                // jestli čudlik muže publikovat tak mu nastavíme QoS/kvalitu služby posílací parametr + retain 
                // a taky napojíme jeho signál 'zpravaOdCudliku' na funkci 'zpravaCudliku'
                if(cudlikJson.muzePublikovat)
                {
                    cudlik.mqttQos = cudlikJson.hasOwnProperty('QoS') ? cudlikJson.QoS : parseInt(0);
                    cudlik.mqttRetain = cudlikJson.hasOwnProperty('retain') ? cudlikJson.retain : false;
                    
                    cudlik.zpravaOdCudliku.connect(zpravaCudliku);
                }
                else
                {
                    cudlik.muzePublikovat = false;
                }
                
                // jestli máme v json definovanej nějakej atribut 'jsonElement' jakože čudlik
                // chce vezprávičkách dycky luštit nějakej json a zněj si něco vyzobnout tak nastavíme že parsuje json
                if(cudlikJson.hasOwnProperty('jsonElement'))
                {
                    cudlik.parsujeJson = true;
                    cudlik.jsonElement = cudlikJson.jsonElement;
                }
                
                // jestli pracuje/drží datovej typ v celočíselný podobě nebo ne
                if(cudlikJson.hasOwnProperty('jeCelociselny'))
                {
                    cudlik.jeCelociselny = cudlikJson.jeCelociselny;
                }
                
                // ruzný specifický atributy pro různý druhy čudliků
                switch(cudlikJson.druh)
                {
                    
                    case 'Prepinadlo':
                        if(cudlikJson.hasOwnProperty('zpravaPriOn'))
                            cudlik.zpravaPriOn = cudlikJson.zpravaPriOn;
                        if(cudlikJson.hasOwnProperty('zpravaPriOff'))
                            cudlik.zpravaPriOff = cudlikJson.zpravaPriOff;
                        if(cudlikJson.hasOwnProperty('onText'))
                            cudlik.onText = cudlikJson.onText;
                        if(cudlikJson.hasOwnProperty('offText'))
                            cudlik.offText = cudlikJson.offText;
                        
                        // aktualizace přepínadla protože vokamžitě nemá barvičku
                        cudlik.aktualizovatCudlik();
                        break;
                        
                    case 'Soupatko':
                    case 'Kruh':
                        if(cudlikJson.hasOwnProperty('minHodnota'))
                            cudlik.hodnotaMin = cudlikJson.minHodnota;
                        if(cudlikJson.hasOwnProperty('maxHodnota'))
                            cudlik.hodnotaMax = cudlikJson.maxHodnota;
                        if(cudlikJson.hasOwnProperty('znakyZaHodnotou'))
                            cudlik.znakyZaHodnotou = cudlikJson.znakyZaHodnotou;
                        
                        console.log(cudlik.hodnotaMin);
                        console.log(cudlikJson.hodnotaMin);
                        
                        if(cudlikJson.druh == 'Kruh')
                            cudlik.aktualizovatPrumerTakyStred();
                        
                        break;
                        
                    case 'Graf':
                        if(cudlikJson.hasOwnProperty('pocetCarMrizky'))
                            cudlik.pocetCarMrizky = cudlikJson.pocetCarMrizky;
                        break;
                    case 'Tlacitko':
                        if(cudlikJson.hasOwnProperty('coPosila'))
                            cudlik.coPosila = cudlikJson.coPosila;
                        if(cudlikJson.hasOwnProperty('napis'))
                            cudlik.napis = cudlikJson.napis;
                        break;
                        
                    case 'Moznosti':
                        if(cudlikJson.hasOwnProperty('seznamMoznosti'))
                            cudlik.seznamMoznosti = cudlikJson.seznamMoznosti;
                        break;
                        
                    case 'Napis':
                        if(cudlikJson.hasOwnProperty('maOkraj'))
                            cudlik.maOkraj = cudlikJson.maOkraj;
                        break;
                        
                    default:
                        console.error('neznamej druch cudliku v json souboru :O :O');
                        break;
                }
                
                
                // přijímací čudliky si rozškatulkujem do polí(slovníků) kde klíčem je topic danýho čudliku dycky
                // nebudem si pak muset přestrkávat zprávu vod mqtt klienta do všech čudliků najednou ale
                // jenom do čudliků danýho topicu
                // máme dvě takový pole polí přijímacích čudliků jedno vobyčejný a druhý pro json
                if(cudlikJson.muzePrijimat)
                {
                    if(cudlik.parsujeJson)
                    {
                        if(cudlikJson.topic in jsonCudlikyPodleTopicu)
                            jsonCudlikyPodleTopicu[cudlikJson.topic].push(cudlik);
                        else
                            // jestli neni tak přidáme nový pole
                            jsonCudlikyPodleTopicu[cudlikJson.topic] = [cudlik];
                    }
                    else
                    {
                        if(cudlikJson.topic in cudlikyPodleTopicu)
                            cudlikyPodleTopicu[cudlikJson.topic].push(cudlik);
                        else
                            cudlikyPodleTopicu[cudlikJson.topic] = [cudlik];
                    }
                }
                else
                {
                    cudlik.muzePrijimat = false;
                }

                // strčíme čudlik do pole který má referenci na všecky čudliky
                vseckyCudliky.push(cudlik);
                
                // jestli čudlik muže publikovat tak taky skováme do pole publikovacích čudliků
                if(cudlik.muzePublikovat)
                    publikovaciCudliky.push(cudlik);
                
                // nakonec skusíme přidat QoS/topic do tý pomyslný 'sady' ze dvou polí
                // topic přidáváme jenom když eště v poli neni. když je tak kouknem jestli je přidávaný qos věčí než to uložený
                // a jestli jako jo tak přepišem
                if(seznamTopicu.includes(cudlikJson.topic))
                {
                    var index = seznamTopicu.indexOf(cudlikJson.topic);
                    if(seznamTopicuQoS[index] < cudlikJson.QoS)
                        seznamTopicuQoS[index] = cudlikJson.QoS;
                }
                else
                {
                    // jestli topic eště v 'sadě' neni tak prostě jako přidáme
                    seznamTopicu.push(cudlikJson.topic);
                    seznamTopicuQoS.push(cudlikJson.QoS);
                }

            }
            
        }
        
        // funkce co vodstraní všecky čudliky
        function odstranitCudliky()
        {
            vseckyCudliky.forEach(cudlik => {cudlik.destroy();});
            vseckyCudliky = [];
            
            publikovaciCudliky = [];
            cudlikyPodleTopicu = [];
            jsonCudlikyPodleTopicu = [];
            
            // seznam topiců promažem taky
            seznamTopicu = [];
            seznamTopicuQoS = [];
        }
        
        // funcke co podle topicu strčí nějakou zprávu všem čudlikům 
        function strcitZpravuCudlikum(topic, obsah)
        {
            console.log('zprava cudlikum topic: ' + topic);
            cudlikyPodleTopicu[topic].forEach(cudlik => {cudlik.prijmout(obsah);});
        }
        
        // tosamý co 'strcitZpravuCudlikum' ale s json
        function strcitJsonZpravuCudlikum(topic, obsah)
        {
            var json = null;
            try
            {
                json = JSON.parse(obsah);
            }
            catch(e)
            {
                console.error('chyba pri parsovani json zpravy: ' + e.name + ', ' + e.message);
            }
            console.log('json zprava cudlikum topic: ' + topic);
            jsonCudlikyPodleTopicu[topic].forEach(cudlik => {cudlik.prijmoutJson(json);});
        }
        
        // zpráva vod čudliku
        // klient ji zkusí poslat (stav připojení si hlídá metoda 'poslat')
        function zpravaCudliku(topic, obsah)
        {
            console.log('posilam str: '+obsah);
            Klient.poslat(topic, obsah);
        }
        
        // callbacky na vodpojení/připojení/chybu klienta
        // vypnem posílací čudliky
        function odpojeniKlienta()
        {
            malejTextDole.text = 'odpojeno (posílací čudliky teďko nefungujou)';
            publikovaciCudliky.forEach(cudlik => {cudlik.muzePublikovat = false;});
        }
        
        // zapnem posílací čudliky
        function pripojeniKlienta()
        {
            malejTextDole.text = 'připojeno';
            publikovaciCudliky.forEach(cudlik => {cudlik.muzePublikovat = true;});
        }
        
        function chybaKlienta(popis)
        {
            if(popis === undefined)
                malejTextDole.text = 'chyba :D';
            else
                malejTextDole.text = popis;
        }
        
        // funkce co se zavolá jakmile máme qml voběkt kompletní
        Component.onCompleted:
        {

            // napojení signálů z mqtt klienta na vodpovídající funkce tady
            Klient.zpravaDoFrontendu.connect(strcitZpravuCudlikum);
            Klient.zpravaJsonDoFrontendu.connect(strcitJsonZpravuCudlikum);
            
            Klient.odpojenej.connect(odpojeniKlienta);
            Klient.pripojenej.connect(pripojeniKlienta);
            Klient.chyba.connect(chybaKlienta);
            
            // jestli máme v kongiguraci uloženej string json souboru tak ho vemem jinak použijem ten výchozí
            var konfiguracniJsonStr = plasmoid.configuration.konfiguracniJson || jsonString;
            
            // zkisíme json naparsovat
            var json = null;
            try
            {
                json = JSON.parse(konfiguracniJsonStr);
            }
            catch(e)
            {
                console.error('chyba pri parsovani konfiguracniho *.json: ' + e.name + ', ' + e.message);
                malejTextDole.text = 'nešlo naparsovat json :O :O';
            }
            
            if(json != null)
            {
                // jestli máme validní json tak podle něj mužem vyrobit čudliky :D ;D
                jsonNaElementy(json);
                
                // nastavíme seznam 
                Klient.nastavitSeznamTopicu(seznamTopicu, seznamTopicuQoS);
                
                // jestli máme nastavenou brokera/přihlašovací ůdaje a klient neni puštěnej tak ho nastavíme a zapnem
                if(adresa && id && uzivatel && heslo)
                {
                    if(!Klient.bezi())
                    {
                        Klient.nastavit(adresa, id, uzivatel, heslo);
                        Klient.start();
                    }
                    else
                    {
                        // sem by jsme se jako vubec neměli dostat :D
                        console.log('mqtt klient uz bezi :O :O');
                    }
                }
                else
                {
                    var txt = 'mqtt klient se nespustil protoze neni nakonfigurovanej';
                    console.log(txt);
                    malejTextDole.text = txt;
                }
            }
            
        }
        
        // když odstraníme widget tak taky jako musíme vipnout mqtt klienta ;D
        Component.onDestruction:
        {
            Klient.stop();
        }
        
        
        //regování na změnu konfigurace
        Plasmoid.onUserConfiguringChanged:
        {
            var konfiguracniJsonStr = plasmoid.configuration.konfiguracniJson || jsonString;
            var json = null;
            try
            {
                json = JSON.parse(konfiguracniJsonStr);
            }
            catch(e)
            {
                console.error('chyba pri parsovani konfiguracniho *.json: ' + e.name + ', ' + e.message);
                malejTextDole.text = 'nešlo naparsovat json :O :O';
            }
            
            if(json != null)
            {
                odstranitCudliky();
                jsonNaElementy(json);
                Klient.nastavitSeznamTopicu(seznamTopicu, seznamTopicuQoS);
                
                if(adresa && id && uzivatel && heslo)
                {
                
                    // jestli klient už běží tak mu resetnem
                    // to znamená že ho vodpojíme přepišem parametry a připojíme znova
                    // vlákno se nepřetrhne :D
                    if(Klient.bezi())
                    {
                        Klient.reset(adresa, id, uzivatel, heslo, seznamTopicu, seznamTopicuQoS);
                    }
                    else
                    {              
                        // jinak normálně pustíme
                        Klient.nastavit(adresa, id, uzivatel, heslo);
                        Klient.start();
                    }
                
                }
                else
                {
                    // jestli je konfigurace špatná/nějakej údaj chybí tak se klient nezačne připojovat
                    var txt = 'mqtt klient se nespustil protoze neni nakonfigurovanej';
                    console.log(txt);
                    malejTextDole.text = txt;
                }
                
            }
        }
        
        
        /*
        *  TODO 
        * todleto se nikdy nezavovlalo :O :O
        *  kolibáč by si tam naně měl pořádně došlápnout aby to tam dali dopořádku si myslim :O :O
        * 
        * 
        Plasmoid.onFormFactorChanged:
        {
            console.log("zmena rozliseni");
        }
        
        Plasmoid.onAvailableScreenRegionChanged:
        {
            console.log("zmena!!!!!!!!!!");
        }
        
        Plasmoid.onLocationChanged:
        {
            console.log("zmena222!!!!!!!!!!");
        }
        */
        
        
        // grid/mřížka do který se nastrkaj jednotlivý čudliky
        GridLayout
        {
            id: grid
            width: parent.width
            height: parent.height - malejTextDole.height
            rowSpacing: velikostMezer
            columnSpacing: velikostMezer
        }
        
        // malej stavovej textík dole u spodního vokraje widgetu
        // řiká cose právě děje a jestli je widget připojenej/nepřipojenej a takový věci
        Text
        {
            y: grid.height
            id: malejTextDole
            text: 'právě teďko zapnutý'
            color: main.barvaTextu
        }
        
    }

}

package/contents/ui/NastavovaniCudliku.qml

import QtQuick 2.0
import QtQuick.Controls 2.5
import QtQuick.Dialogs 1.0
import QtQuick.Layouts 1.12
import org.kde.kirigami 2.4 as Kirigami

// podle ukázky tady hele https://develop.kde.org/docs/plasma/widget/configuration/

// naimportujem si svuj plugin kuli třídě 'NačítadloSouboru' kterou potřebujem kuli načtení textovýho souboru
// samotný qml nic takovýho jako přečíst nějakej *.txt asi neumí :O :O
import org.kde.private.mqttCudliky 1.0

Kirigami.FormLayout
{
    id: page
    Kirigami.FormData.label: i18n('Nastavování')

    // vyrobení načítadla
    Nacitadlo
    {
        id: nacitadlo
    }
    
    // proměný musej mit ten prefix 'cfg_' aby si to jakože spárovalo s vodpovídajícíma hodnotama v souboru main.xml 
    property alias cfg_adresa: konfiguraceAdresa.text
    property alias cfg_id: konfiguraceId.text
    property alias cfg_uzivatel: konfiguraceUzivatel.text
    property alias cfg_heslo: konfiguraceHeslo.text
  
    property alias cfg_konfiguracniJson: configTxt.text
    
    TextField
    {
        id: konfiguraceAdresa
        Kirigami.FormData.label: i18n('adresa:')
        placeholderText: i18n('adresa s druhem protokolu a portem nakonci. třeba něco jako tcp://127.0.0.1:1883')
    }
        
    TextField
    {
        id: konfiguraceId
        Kirigami.FormData.label: i18n('id klienta')
        placeholderText: i18n('id klienta')
    }

    TextField
    {
        id: konfiguraceUzivatel
        Kirigami.FormData.label: i18n('uživatel')
        placeholderText: i18n('uživatel')
    }
        
    TextField
    {
        id: konfiguraceHeslo
        Kirigami.FormData.label: i18n('heslo')
        placeholderText: i18n('heslo')
    }

    
    ColumnLayout
    {
    Kirigami.FormData.label: i18n('načíst z konfiguračního *.json (umí to načíst i tamto nastavování brokera takže seto nemusí vyplňovat rukama)')
    
    
        TextArea
        {
        id: configTxt
        placeholderText: i18n('tady by měl bejt konfurační json čudliků ukázanej')
        Layout.fillHeight: true
        Layout.fillWidth: true
        }

        Button
        {
            text: i18n('Načíst *.json ze souboru')
            icon.name: 'folder-symbolic'
            onClicked:
            {
                fileDialogLoader.active = true
            }

            // načítadlo souborů
            // soubor dostanem jako proměnou fileUrl toje místo uložení toho souboru někde v systemu
            // asi nám neumí dát přímo jeho vobsah nevim :O :O
            Loader
            {
                id: fileDialogLoader
                active: false

                sourceComponent: FileDialog 
                {
                    id: fileDialog
                    //folder: shortcuts.music
                    
                    // chcem json ale umožníme taky vybrat všecky soubory
                    nameFilters: [i18n('json(%1)', '*.json'),i18n('všecky soubory(%1)', '*'),]
                    
                    onAccepted:
                    {
                        // načtem načítadlem vobsah souboru do js proměný
                        var obsah = nacitadlo.nacistSoubor(fileUrl);
                        
                        // měl byto bejt jakože validní json nóó tak si ho zkusíme tady nejdřiv naparsovat a
                        // když nám to nebude/skončí vyjímkou tak tam asi jako je nějaká chyba
                        var json = null;
                        try
                        {
                            json = JSON.parse(obsah);
                        }
                        catch(e)
                        {
                            configTxt.text = 'chyba pri parsovani konfiguracniho *.json: ' + e.name + ', ' + e.message;
                            console.error(configTxt.text);
                        }
                        
                        if(json != null)
                        {
                            // jestli máme validní json tak ho strčíme do configTxt textovýho pole aby se nám jakože pak uložil do nastavení widgetu
                            configTxt.text = obsah;
                            
                            // jestli má json soubor element pomenovanej 'broker' tak podle něj nastavíme připojení a nemusíme to vyplňovat ručně furt
                            if(json.hasOwnProperty('broker'))
                            {
                                var brokerJson = json.broker;
                                
                                if(brokerJson.hasOwnProperty('adresa'))
                                    konfiguraceAdresa.text = brokerJson.adresa;
                                if(brokerJson.hasOwnProperty('id'))
                                    konfiguraceId.text = brokerJson.id;
                                if(brokerJson.hasOwnProperty('uzivatel'))
                                    konfiguraceUzivatel.text = brokerJson.uzivatel;
                                if(brokerJson.hasOwnProperty('heslo'))
                                    konfiguraceHeslo.text = brokerJson.heslo;
                            }
                            
                        }
                        
                        fileDialogLoader.active = false;
                    }
                    
                    onRejected:
                    {
                        fileDialogLoader.active = false;
                    }
                    
                    Component.onCompleted: open()
                }
            }
        }

    }
    
}
 

package/contents/ui/cudliky/Cudlik.qml

import QtQml 2.2
import QtQuick 2.9
import QtQuick.Layouts 1.11

// oběkt ze kterýho 'děděj' všecky vostatní čudliky 

Rectangle
{

    //nějaká minimalní velikost aby se nám to jakože celý nescvrklo uplně
    Layout.minimumWidth: 64
    Layout.minimumHeight: 64
    
    property string nazev: 'Cudlik'
    
    // výchozí barvy čudliku kdyby třeba jako nebyly přenastavený po vyrobení
    property color barvaTextu: 'black'
    property color barvaAktivni: 'red'
    property color barvaKontury: 'green'
    property color barvaPozadi: 'white'
    
    // tloušťka vokraje a zakulacení vokrajů
    property real velikostOkraje: 5
    property real zakulaceni: 5
    
    // k jakýmu je připojenej topicu s jakým qos/kvalitou služby a jestli je zapnutej retain flag
    property string mqttTopic: ''
    property int mqttQos: 0
    property bool mqttRetain: false
    
    // jestli muže publikovat a přijímat zprávy
    property bool muzePublikovat: true
    property bool muzePrijimat: true
    
    // alias/reference kterou umožňujem potomkům lízt k titulku týdletý třídy
    property alias titulek: titulek
    // alias kterým se nastavuje viditelnost titulku
    property alias maTitulek: titulek.visible
    
    // jestli jakoby parsuje json a jestli jo tak jakej element hledá
    // žádný složitý parsování prostě koukne na element
    // potřebuje někdo nějaký víc složitější parsování??????? :O :O :O :O
    // sou různý mrňavý knihovničky nato hele třeba https://www.w3resource.com/JSON/JSONPath-with-JavaScript.php
    property bool parsujeJson: false
    property string jsonElement: ""
    
    // jestli je double/int
    property bool jeCelociselny: true
    
    // jestli je vubec jako číselnej
    property bool jeCiselny: true
    
    color: Qt.rgba(0,0,0,0)
    
    // funkce do který se budou strkat přijatý zprávy
    // nevim jak to udělat jako abstraktní metodu :D
    function prijmout(zprava){console.log("zavolano cudlik.prijmout rodicovsky tridy :O :O");}
    
    // funkce co zkusí vyparsovat klíč z json zprávičky aten pak strčit do normální funkce přijmout
    // potomci Čudliku todleto teda pak nemusej řešit
    function prijmoutJson(zpravaJson)
    {
        if(parsujeJson)
        {
            if(zpravaJson.hasOwnProperty(jsonElement))
            {
                prijmout(zpravaJson[jsonElement]);
            }
            else
            {
                console.error('v json zprave neni tendlecten klic/element!!!!!!!!!!!!!!!');
            }
        }
        else
        {
            console.error('tendle cudlik nechce json parsovat!!!!!!!!!!!!!!');
        }
        
    }
    
    // titulek čudliku kterej se věčinou zobrazuje nad tim elementem
    Text
    {
        id: titulek
        text: "Cudlik"
        color: parent.barvaTextu
//         font.pointSize: 16
            // velikost fontu se vybírá sama podle width/height velikosti Text voběktu
            font.pointSize: 256
            minimumPointSize: 8
            fontSizeMode: Text.Fit
        
        width: parent.width
        height: parent.height/5
        visible: true
    }
}

package/contents/ui/cudliky/Graf.qml

import QtQuick 2.9
import QtQuick.Controls 2.5
import org.kde.quickcharts 1.0 as Charts
import org.kde.quickcharts.controls 1.0 as ChartsControls

// čudlik s kcharts grafem
// api maj trošičku popsaný tady https://api.kde.org/frameworks-api/frameworks-apidocs/frameworks/kquickcharts/html/index.html
// ale blbě se k tomu hledaj nějaký víc složitější ukázkový příklady :O :/

Cudlik 
{
    id: grafRoot
    nazev: "graf"
    titulek.text: nazev
    
    property real zobrazovanaPromena: 0
    property var zdrojDat: Charts.SingleValueSource { value: zobrazovanaPromena }
    property int pocetCarMrizky: 3
    
    function prijmout(zprava)
    {
        grafRoot.zobrazovanaPromena = jeCelociselny ? parseInt(zprava) : parseFloat(zprava);
        grafRoot.zdrojDat.dataChanged();
    }
        
    Rectangle
    {
        width: parent.width
        height: titulek.visible ? parent.height - titulek.height : parent.height
        y: titulek.visible ? titulek.height : 0
        
        color: barvaPozadi
        radius: zakulaceni
        
        
        Charts.LineChart
        {
            id: grafPlot
            antialiasing: true
            anchors.verticalCenter: parent.verticalCenter
            x: yAxisLabels.width + velikostOkraje + 10

            width: parent.width - velikostOkraje*2 - yAxisLabels.width -10
            height: parent.height - velikostOkraje*2
        
            colorSource: Charts.SingleValueSource { value: barvaAktivni }
            nameSource: Charts.SingleValueSource { value: nazev }
            valueSources: Charts.HistoryProxySource 
            {
                source: grafRoot.zdrojDat
                maximumHistory: 100
            }
                
            lineWidth: 2
            fillOpacity: 0.5
            smooth:false
            direction:Charts.XYChart.ZeroAtEnd
                
                
        
            Charts.GridLines
            {
                id: vertikalni
    
                anchors.fill: parent
                chart: parent
                direction: Charts.GridLines.Vertical;
    
                minor.count: pocetCarMrizky
                minor.lineWidth: 1
                minor.color: barvaTextu
                
                // major čáry se mi nepodařilo uplně vypnout
                // když se třeba jako do major.count strčí 0 tak si je to asi generuje podle .frequency atributu :O :/
                major.count: 1
                major.lineWidth: 1
                major.color: barvaTextu
           
            }
            
            Charts.GridLines
            {
                id: horizontalni
    
                anchors.fill: parent
                chart: parent
                direction: Charts.GridLines.Horizontal;
    
                minor.count: pocetCarMrizky
                minor.lineWidth: 1
                minor.color: barvaTextu
                
                major.count: 1
                major.lineWidth: 1
                major.color: barvaTextu
            }
            
            Rectangle
            {
                id: okrajMrizky
                anchors.fill: parent
                color: Qt.rgba(0,0,0,0)
                border.color: barvaTextu
                border.width: 1
            }
            
        }
            
        Charts.AxisLabels
        {
            id: yAxisLabels
            anchors.verticalCenter: parent.verticalCenter

            height: parent.height - velikostOkraje*2
            x: 10
    
            direction: Charts.AxisLabels.VerticalBottomTop
            
            // nejde to ňák víc líp???? :O :O
            delegate: Label
            {
                color: barvaTextu
                text: parseFloat(Charts.AxisLabels.label).toFixed(2);
            }
            
            source: Charts.ChartAxisSource 
            {
                chart: grafPlot
                axis: Charts.ChartAxisSource.YAxis
                itemCount: pocetCarMrizky + 2
            }
        }
    
    
        Rectangle
        {
            id: okrajGrafu
            anchors.fill: parent
            color: Qt.rgba(0,0,0,0)
            border.color: barvaKontury
            border.width: velikostOkraje
            radius: zakulaceni
        }
    
    }
}

package/contents/ui/cudliky/Kruh.qml

import QtQml 2.2
import QtQuick 2.9

// takový jakože kolečko
// kolečko uměj namalovat i kcharts ale to sem zistila až když sem měla todleto hotový :D

Cudlik
{
    id: kruh
    
    nazev: "Kruh"
    
    // minimální maximální hodnota aktuální hodnota a možnej rosah hodnoty
    property real hodnotaMin: 0
    property real hodnotaMax: 100
    property real hodnota: 100
    property real rosahHodnot: hodnotaMax - hodnotaMin
    
    // jaký znaky se voběvujou za hodnotou uprostřed toho kruhu
    // výchozí je znak '%'
    property string znakyZaHodnotou: '%'
    titulek.text: nazev
    property real sirkaHlavniCary: 16
    property real sirkaVedlejsiCary: velikostOkraje
    property real offset_cary: 1
    
    // souřadnice středu toho kruhu a jeho poloměr
    // jeto vymyšlený tak že když je titulek kračí než zdálenost středu kruhu vod levýho/pravýho vokraje tak
    // se kruh do volnýho místa nafoukne. jinak je menčí než titulek a stčenej vo velikost titulku dolu abyseto jakože nepřekrejvalo
    // protože byto bylo takový hnusný
    
    // x je dycky uprostřed
    property real stredX: width / 2
    property real stredY: height /2
    property real polomer: height / 2
    
    // polomer je vlastně jenom poloměr kružnice podle který namalujem nějak tlustej kroužek
    // noa půlka tloušťky tohodlenctoho kroužku je atribut polomerOffset
    property real polomerOffset: sirkaHlavniCary/2 + sirkaVedlejsiCary
        
    // přepočet aktuální hodnoty na úhel v radiánech
    property real uhel: (kruh.hodnota - kruh.hodnotaMin) / kruh.rosahHodnot * 2 * Math.PI

    // posun úhlu aby nula byla na kružnici uplně nahoře (tam kde maj točicí hodiny dvanáctku)
    property real posunUhlu: -Math.PI / 2
    
    // naparsujem číslo podle toho jestli je float nebo celočíselný
    function prijmout(zprava)
    {
        hodnota = jeCelociselny ? parseInt(zprava) : parseFloat(zprava);
    }
    
    // výpočet poloměru podle toho kde se kružnice zdrcne s titulkem
    function aktualizovatPrumerTakyStred()
    {
        
        // když nemá titulek tak vemem to menčí z width/šířky a height/vejšky a podle toho uděláme ten poloměr
        // v polovině velikost - půlka tloušťky toho našeho malovacího kroužku
        if(!maTitulek)
        {
            kruh.polomer = (Math.min(kresliciPlocha.width, kresliciPlocha.height) - sirkaHlavniCary - sirkaVedlejsiCary) / 2 - offset_cary;
        }
        else if(titulek.width < stredX)
        {
            // když je titulek kratčí a dělá že končí před xovým středem nažeho zobrazovacího kroužku tak skusíme najít tu nejvíc nejvěčí kružnici
            // kterou tam mužem strčit. tadleta kružnice muže dosáhnout až na pravej dolní růžek titulku jestli ji to dovolej rozměry kreslicí plochy
            
            // do rovnice pro kružnici hele https://cs.wikipedia.org/wiki/Kru%C5%BEnice
            // (bod.x - střed.x)**2 + (bod.y - střed.y)**2 == r**2
            // si dosadíme za bod na vobvodu ten pravej dolní růžek titulku
            // a za střed.y vejšku kreslicí plochy - poloměr, jakože vejšku vod spodního vokraje
            // luštěnej zoreček třeba takle nějak
            // (titulek.x - kresliciPlocha.width/2)**2 + (titulek.y - kresliciPlocha.y + r)**2 == r**2
            
            // cejtim žeto de eště trošičku aritmetologicky víc zjednodušit ale sem moc líná nato :D
            // a tamta absolutní hodnota by tam asi jako vubec neměla bejt :D
            var c1 = (titulek.width - stredX)**2;
            var c2 = - titulek.height + kruh.height;
            var r = Math.abs(-(c1/(2*c2)) - (c2/2));
            
            kruh.polomer = Math.abs((Math.min(kresliciPlocha.width/2, kresliciPlocha.height/2, r) - polomerOffset) - offset_cary);
            
        }
        else
        {
            kruh.polomer = (Math.min(kresliciPlocha.width, kresliciPlocha.height - titulek.height) - sirkaHlavniCary - sirkaVedlejsiCary) / 2 - offset_cary;
        }
        
        kruh.stredY = kruh.height - kruh.polomer - polomerOffset;
    }
    
    // ždycky když se změní šířka/vejška widgetu tak přepočitáme ipsilonovou souřadnici středu kroužku + poloměr
    // fakt byse asi jako hodilo vědět jak se jako dělá callback na změnu rozlišení velikosti widgetu a tak si ty hodnoty přepočítávat :D
    onWidthChanged:
    {
        aktualizovatPrumerTakyStred();
    }
    onHeightChanged:
    {
        aktualizovatPrumerTakyStred();
    }

    // překreslíme malovací plochu pokaždý když se změní hodnota
    onHodnotaChanged:
    {
        kresliciPlocha.requestPaint();
        
        // tadleta aktualizace průměrů je tady jenom prozatim než se ňák podaří vymyslet jak to jako
        // aktualizovat nějak líp :O :O
        aktualizovatPrumerTakyStred();
    }
    // .. a taky když vyrobíme element
    Component.onCompleted: kresliciPlocha.requestPaint()

    //kreslicí plocha na který si budem malovat ty kroužky
    Canvas
    {
        id: kresliciPlocha
        width: kruh.width
        height: kruh.height
        
        // všecko je víc hežčí s antialiasingem :D ;D
        antialiasing: true

        onPaint:
        {
            // vezmem 2d kreslicí kontext a vypucujem 
            var ctx = getContext('2d');
            //ctx.save();
            ctx.clearRect(0, 0, kresliciPlocha.width, kresliciPlocha.height);

            //nakreslení pozadí
            ctx.beginPath();
            ctx.lineWidth = sirkaHlavniCary;
            ctx.strokeStyle = kruh.barvaPozadi;
            ctx.arc(kruh.stredX, kruh.stredY, kruh.polomer, 0, 2*Math.PI);
            ctx.stroke();
            
            //nakreslení zobrazovací čáry
            ctx.beginPath();
            ctx.lineWidth = sirkaHlavniCary;
            ctx.strokeStyle = kruh.barvaAktivni;
            ctx.arc(kruh.stredX, kruh.stredY, kruh.polomer, kruh.posunUhlu, kruh.posunUhlu + kruh.uhel);
            ctx.stroke();

            // a nakreslení vobou dvou krajních vokrajovejch čar
            ctx.beginPath();
            ctx.lineWidth = sirkaVedlejsiCary;
            ctx.strokeStyle = kruh.barvaKontury
            ctx.arc(kruh.stredX, kruh.stredY, kruh.polomer - sirkaHlavniCary/2 - offset_cary, 0, 2*Math.PI);
            ctx.stroke();
            
            ctx.beginPath();
            ctx.lineWidth = sirkaVedlejsiCary;
            ctx.strokeStyle = kruh.barvaKontury
            ctx.arc(kruh.stredX, kruh.stredY, kruh.polomer + sirkaHlavniCary/2 + offset_cary, 0, 2*Math.PI);
            ctx.stroke();

            //ctx.restore();

        }

        // takovej ten text uprostřed kruhu
        Text
        {
            anchors.horizontalCenter: parent.horizontalCenter
            y: kruh.stredY - height/2
            verticalAlignment: Text.AlignVCenter


            // jestli neni celočíselnej ukazujem proměnou jenom se dvouma desetinovejma místama
            text: ( jeCelociselny ? parseInt(kruh.hodnota) : kruh.hodnota.toFixed(2) ) + znakyZaHodnotou
            color: kruh.barvaTextu
            width: kruh.polomer*1.2
            height: kruh.polomer*1.2
            
            // velikost fontu se vybírá sama podle width/height velikosti Text voběktu
            font.pointSize: 256
            minimumPointSize: 8
            fontSizeMode: Text.Fit
        }
        
        // klikací voblast kruhu
        // je aktivní jenom když čudlik muže publikovat 
        // funguje tak že když se klikne někde na kruhu tak se hodnota nastaví tak aby jakože tomu 
        // kliknutýmu místo proporcionacionálně vodpovídala
        MouseArea
        {
            anchors.fill: parent
            enabled: muzePublikovat
            onClicked:
            {
                // spočitáme euklidovskou zdálenost
                var zdalenost = Math.sqrt( (mouse.x - kruh.stredX)**2 + (mouse.y - kruh.stredY)**2 );
                
                // nastavujem hodnotu jenom když se myškou máčkne přímo tamten kruh
                // věčí/menčí zdálenosti nepočitáme
                if(zdalenost > kruh.polomer - kruh.polomerOffset && zdalenost < kruh.polomer + kruh.polomerOffset)
                {      
                    // vodečtem vod máčknutý souřadnice střed kruhu takže střed kružnice je teďko jakoby na bode (0,0)
                    var x = mouse.x - kruh.stredX
                    var y = mouse.y - kruh.stredY
                    
                    // pomocí atan2 spočitáme jakej má bod máčknutí uhel v rosahu od mínus pí až plus pí
                    // tendleten uhel pak mužem převíst třeba na hodnotu v rosahu 0.0 až 2.0 atu pak násobit půlkou
                    // maximální možný hodnoty kterou čudlik muže ukazovat/mit 
                    kruh.hodnota = (1.0 - (Math.atan2(x, y) / Math.PI)) * kruh.rosahHodnot/2 + kruh.hodnotaMin;
                    
                    // nakonec pošlem
                    zpravaOdCudliku(mqttTopic, jeCelociselny ? parseInt(kruh.hodnota) : kruh.hodnota);
                }
                
            }
        }
    }


}

package/contents/ui/cudliky/Moznosti.qml

import QtQml 2.2
import QtQuick 2.15
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Templates 2.4 as QtSablony

//jeto vlastně combobox ve kterým je strčený nějaký políčko stringů ze kterýho si mužem vybírat jednu možnost dycky

Cudlik
{
    id: moznostiRoot
    
    nazev: 'moznosti'
    titulek.text: nazev
    property var seznamMoznosti: ['tady','by měl', 'bejt seznam','možností']
    
    function prijmout(zprava)
    {
        if(!muzePrijimat)
            return;

        // jestli přijatá zpráva vodpovídá některý hodnotě v poli možností tak se nastaví 
        // index právě vybraný možnosti
        // ( atribut currentText qml voběktu https://doc.qt.io/qt-5/qml-qtquick-controls-combobox-members.html je jenom pro čtení :O :/ )
        if(seznamMoznosti.includes(zprava))
                vybiradlo.currentIndex = vybiradlo.find(zprava);
    }

    ComboBox
    {
        id: vybiradlo
        
        width: parent.width
        height: maTitulek ? parent.height - titulek.height : parent.height
        y: maTitulek ? titulek.height : 0
        
        model: seznamMoznosti
        
        // možnost je vybíratelná jenom když de publikovat
        selectByMouse: muzePublikovat
        
        // nahradíme původní barvičky tlačítka svejma nějakejma
        // neví někdo jak jako přestylovat do dropdownový menu :O :O
        // tendlecten návod hele https://doc.qt.io/qt-5/qtquickcontrols2-customize.html#customizing-combobox nefunguje :O :/
        style: ComboBoxStyle 
        {
            
            font.pointSize: 24
            textColor: 'black'
            selectedTextColor: barvaKontury
            selectionColor: barvaAktivni
            
            background: Rectangle
            {
                height: control.height
                width: control.width
                color : barvaPozadi
                border.color: barvaKontury
                border.width: velikostOkraje
                radius: zakulaceni
            }
            
            // text strčíme doprostřed a nafouknem aby byl co nejvíc nejvěčí
            label: Text    
            {

                //verticalAlignment: Text.AlignVCenter
                anchors.centerIn: vybiradlo
                text:  control.editText
                color: barvaTextu
                width: control.width - velikostOkraje*2
                height: control.height - velikostOkraje*2
                
                font.pointSize: 256
                minimumPointSize: 8
                fontSizeMode: Text.Fit
            }
            
        }
        
        onActivated:
        {
            zpravaOdCudliku(mqttTopic, seznamMoznosti[index]);
        }
    }
    


}

package/contents/ui/cudliky/Napis.qml

import QtQml 2.2
import QtQuick 2.15

// takovej jakože hodně moc vobyčejnej čudlik kterej dělá jenom to že ukazuje text nějakej chycenej

Cudlik
{
    id: napisRoot
    
    nazev: "napis"
    titulek.text: nazev
    
    property alias text: napisElement.text
    
    // jestli má nějaký pozadí/vokraj 
    // když ne ukazuje se jenom samotnej textík přímo na widgetu
    property bool maOkraj: true
    
    function prijmout(zprava)
    {
        if(!muzePrijimat)
            return;
        text = zprava;
    }

    Rectangle
    {
        id: okraj
        width: parent.width
        height: maTitulek ? parent.height - titulek.height : parent.height
        radius: zakulaceni
        y: maTitulek ? titulek.height : 0

        color: barvaPozadi
        border.color: barvaKontury
        border.width: velikostOkraje
                
        visible: maOkraj
    }
        
    Text
    {
        id: napisElement
        text: "napis"
        width: okraj.width - velikostOkraje * 2
        height: okraj.height - velikostOkraje * 2
        anchors.centerIn: okraj
        horizontalAlignment: Text.AlignHCenter
        verticalAlignment: Text.AlignVCenter

        color: barvaTextu
                
        font.pointSize: 256
        minimumPointSize: 8
        fontSizeMode: Text.Fit

    }
    
    


}

package/contents/ui/cudliky/Prepinadlo.qml

import QtQml 2.2
import QtQuick 2.15

// mačkátko který funguje jako takovej jakože přepínač
// má dva stavy zapnuto vypnuto

Cudlik
{
    id: prepinadlo
    
    nazev: 'prepinadlo'
    
    // jestli je zapnutej nebo vypnutej
    property bool stav: false
    
    // podle jakýho vobsahu chycený zprávy mění svuj stav
    // todleto taky posílá při zapnutí/vypnutí
    property string zpravaPriOn: '1'
    property string zpravaPriOff: '0'
    
    // co je na něm jako napsaný při zapnutí/vypnutí
    property string onText: 'ON'
    property string offText: 'OFF'
    
    // vypnem normální titulek třídy Čudlik
    // budem si malovat nějakej nezávislej na to mačkátko přímo
    titulek.visible: false

    // mačkátko je takovej jakože čtvereček
    // velikost strany čtverečku bude to víc menčí z dýlky a šířky elementu 
    property real stranaTlacitka: Math.min(width, height)
    
    function prijmout(zprava)
    {
        if(!muzePrijimat)
            return;
        
        // nastavíme stav podle toho jestli jako string zprávičky vodpovídá
        // zpravaPriOff nebo zpravaPriOn a aktualizujem zobrazení čudliku
        if(zprava === zpravaPriOff)
        {
            stav = false;
            aktualizovatCudlik();
        }
        else if(zprava === zpravaPriOn)
        {
            stav = true;
            aktualizovatCudlik();
        }
    }
    
    // prostě jako přebarvíme součástky čudliku podle stavu kterej má
    // a změníme vobsah zobrazovanejch textů
    function aktualizovatCudlik()
    {
        if(stav)
        {
            mackatko.color = barvaAktivni;
            onOffText.color = barvaKontury;
            onOffTitulek.color = barvaKontury;
            onOffText.text = onText;
        }
        else
        {
            mackatko.color = barvaPozadi;
            onOffText.color = barvaTextu;
            onOffTitulek.color = barvaTextu;
            onOffText.text = offText;
        }
        
    }
    
    // když se nám změní hodnota proměný stav tak taky aktualizujem zobrazení čudliku
    onStavChanged: aktualizovatCudlik()
    
    Rectangle
    {
        id: mackatko
        radius: zakulaceni
        
        width: parent.stranaTlacitka
        height: parent.stranaTlacitka
        
        // vypolohujem doprostředka
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottom: parent.bottom
        
        // barva a tloušťka vokraje rectanglu/čtverečku
        border.color: barvaKontury
        border.width: velikostOkraje
        
        MouseArea
        {
            id: mouseArea
            anchors.fill: parent
            enabled: muzePublikovat
            
            onClicked:
            {
                prepinadlo.stav = !prepinadlo.stav;
                zpravaOdCudliku(mqttTopic, prepinadlo.stav ? zpravaPriOn : zpravaPriOff);
            }
        }
        
        // text uprostřed čudliku kterej popisuje jestli je mačkátko zapnutý/vypnutý
        Text
        {
            id: onOffText
            anchors.centerIn: mackatko
            
            verticalAlignment: Text.AlignVCenter
            width: parent.width/2
            height: parent.height/2
            
            font.pointSize: 256
            minimumPointSize: 8
            fontSizeMode: Text.Fit
        }
        
        // titulek/název čudliku zobrazovanej přímo na mačkátku
        Text
        {
            id: onOffTitulek
            text: prepinadlo.nazev
            
            anchors.horizontalCenter: parent.horizontalCenter
            
            verticalAlignment: Text.AlignVCenter
            horizontalAlignment: Text.AlignHCenter
            width: parent.width/2
            height: parent.height/2
            
            font.pointSize: 256
            minimumPointSize: 8
            fontSizeMode: Text.Fit
        }
    }

}

package/contents/ui/cudliky/Soupatko.qml

import QtQml 2.2
import QtQuick 2.15
import org.kde.plasma.components 3.0 as PlasmaComponents

// takový posouvátko
// jeto taková jakože vlastní trošičku horší varianta něčeho na
// způsob slideru https://doc.qt.io/qt-5/qml-qtquick-controls-slider.html
// máme nějakej čtvereček pomenovanej 'šoupací element' a ten mužem tahat po ose x

Cudlik
{
    id: soupatkoRoot
    nazev: 'soupatko'
    
    property int hodnotaMin: 0
    property int hodnotaMax: 100
    
    property string znakyZaHodnotou: '%'
    titulek.text: nazev + ' ' + 50 + znakyZaHodnotou
    
    
    function prijmout(zprava)
    {
        if(!muzePrijimat)
            return;
        
        var podil = (parseInt(zprava) - hodnotaMin) / (hodnotaMax - hodnotaMin);
        soupaciElement.x = maxRosah * podil + velikostOkraje;
        
        // jestli zobrazuje titulek za název připišem aktuální hodntou a znaky který za hodnotou ukazujem 
        if(maTitulek)
        {
            titulek.text = nazev + " " + poziceNaHodnotu() + znakyZaHodnotou;
        }
    }
    
    // přepočet xový hodnoty šoupacího elementu na hodntou
    function poziceNaHodnotu()
    {
        var podil = (soupaciElement.x - velikostOkraje) / maxRosah;
        return parseInt((hodnotaMax - hodnotaMin) * podil + hodnotaMin);
    }
    
    // možnej rosah xový souřadnice šoupacího elementu 
    property real maxRosah: okraj.width - soupaciElement.width - velikostOkraje*2
    
    // pozadí šoupátka
    Rectangle
    {
        id: pozadi
        height: parent.height/4
        width: parent.width

        anchors.verticalCenter: parent.verticalCenter
        color: barvaPozadi
        radius: zakulaceni
        
        // když pozadí máčken myšičkou tak taky aktualizujem polohu šoupátka + hodnotu čudliku
        MouseArea
        {
            anchors.fill: parent
            enabled: muzePublikovat
            onClicked:
            {
                var x = mouse.x;
                if(x < velikostOkraje)
                    x = velikostOkraje;
                else if(x > maxRosah)
                    x = maxRosah + velikostOkraje;
                
                soupaciElement.x = x;
                zpravaOdCudliku(mqttTopic, poziceNaHodnotu());
            }
        }
        
        // něco jako takovej jakože progress bar kterej vyplňuje voblast vod levýho vokraje až po šoupací element
        Rectangle
        {
            id: progress
            x: 1
            y: 1
            height: pozadi.height - 2
            width: soupaciElement.x + soupaciElement.width/2 -2
            color: barvaAktivni
            radius: zakulaceni
        }
        
        // vokraj šoupátka
        Rectangle
        {
            id: okraj
            border.color: barvaKontury
            border.width: velikostOkraje
            color: Qt.rgba(0,0,0,0);
            height: pozadi.height
            width: pozadi.width
            radius: zakulaceni
        }
        
        // samotnej šoupací element
        Rectangle
        {
            id: soupaciElement
            width: 32
            anchors.verticalCenter: pozadi.verticalCenter
            height: pozadi.height * 2
            radius: zakulaceni
            color: barvaTextu
            border.color: barvaKontury
            border.width: velikostOkraje
            
            // ždycky když se změní xová souřadnice tak aktualizujem titulek jestli ho zobrazujem teda
            onXChanged:
            {
                if(maTitulek)
                    titulek.text = nazev + ' ' + poziceNaHodnotu() + znakyZaHodnotou;
            }
            
            MouseArea
            {
                anchors.fill: parent
                enabled: muzePublikovat
                
                // uděláme ho dragable/tahatelnej myšičkou
                drag.target: soupaciElement
                
                // tahat pude jenom po ose x
                drag.axis: Drag.XAxis
                
                // vodkaď až kam ho jako pude tahat
                drag.minimumX: velikostOkraje
                drag.maximumX: okraj.width - soupaciElement.width - velikostOkraje
                
                onReleased:
                {
                    zpravaOdCudliku(mqttTopic, poziceNaHodnotu());
                }
                
            }
        }
        
        
    }
    
    
}

package/contents/ui/cudliky/Tlacitko.qml

import QtQml 2.2
import QtQuick 2.15
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Templates 2.4 as QtSablony

//jeto vlastně combobox ve kterým je strčený nějaký políčko stringů ze kterýho si mužem vybírat jednu možnost dycky

Cudlik
{
    id: tlacitkoRoot
    
    nazev: 'Tlacitko'
    titulek.text: nazev
    
    property string napis: nazev
    property string coPosila: 'tlacitko macknuty'
    
    function prijmout(zprava)
    {
        if(!muzePrijimat)
            return;
        
        console.log('tlacitko by asi jako nemelo bejt vubec schopny prijimat mqtt zpravy :O :O');

    }

    Button
    {
        id: tlacitko
        
        width: parent.width
        height: maTitulek ? parent.height - titulek.height : parent.height
        y: maTitulek ? titulek.height : 0
        
        // nahradíme původní barvičky svejma nějakejma
        style: ButtonStyle 
        {
            
            background: Rectangle
            {
                height: control.height
                width: control.width
                color : tlacitko.pressed ? barvaAktivni : barvaPozadi
                border.color: barvaKontury
                border.width: velikostOkraje
                radius: zakulaceni
            }
            
            // text strčíme doprostřed a nafouknem aby byl co nejvíc nejvěčí
            label: Text    
            {

                verticalAlignment: Text.AlignVCenter
                anchors.centerIn: tlacitko
                text:  napis
                color: tlacitko.pressed ? barvaPozadi : barvaTextu
                width: control.width - velikostOkraje*2
                height: control.height - velikostOkraje*2
                
                font.pointSize: 256
                minimumPointSize: 8
                fontSizeMode: Text.Fit
            }
            

            

        }
        
        onClicked:
        {
            zpravaOdCudliku(mqttTopic, coPosila);
        }
    }
    


}

       

Hodnocení: 100 %

        špatnédobré        

Obrázky

plazmový mqtt čudliky na plochu, obrázek 1

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

Komentáře

Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře. , Tisk

Vložit další komentář

Petr Fiedler avatar 30.3.2021 01:25 Petr Fiedler | skóre: 35 | blog: Poradna | Brno
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Odpovědět | Sbalit | Link | Blokovat | Admin

Současný desktop vypadá opravdu dobře.

Gréta avatar 31.3.2021 19:40 Gréta | skóre: 36 | blog: Grétin blogísek | 🇮🇱==❤️ , 🇵🇸==💩 , 🇪🇺==☭
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Max avatar 30.3.2021 09:40 Max | skóre: 72 | blog: Max_Devaine
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Odpovědět | Sbalit | Link | Blokovat | Admin
Moc pěkná práce, díky.
Zdar Max
Měl jsem sen ... :(
1.4.2021 13:28 Jaroš
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Kam to nasadíš?

Regards J.
vencour avatar 30.3.2021 10:06 vencour | skóre: 56 | blog: Tady je Vencourovo | Praha+západní Čechy
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Odpovědět | Sbalit | Link | Blokovat | Admin
Je někdo, kdo by viděl radši jednorožce místo tučňáků? A ve stejném smyslu jako jsou tu tučňáci?
Ty nejhlubší objevy nečekají nutně za příští hvězdou. Jsou uvnitř nás utkány do vláken, která nás spojují, nás všechny.
30.3.2021 10:17 figliar0 | skóre: 6 | blog: figliarstva | Košice
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Ne.
Max avatar 30.3.2021 11:28 Max | skóre: 72 | blog: Max_Devaine
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Ne
Zdar Max
Měl jsem sen ... :(
vencour avatar 30.3.2021 18:28 vencour | skóre: 56 | blog: Tady je Vencourovo | Praha+západní Čechy
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Ok, jiný styl to vyřeší, někdo doma bude mít radost :-) až uvidí jednorožce :-)
Ty nejhlubší objevy nečekají nutně za příští hvězdou. Jsou uvnitř nás utkány do vláken, která nás spojují, nás všechny.
Max avatar 30.3.2021 11:29 Max | skóre: 72 | blog: Max_Devaine
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
BTW, nic ti asi nebrání v tom si vytvořit vlastní styl s jednorožcem místo tučňáka.
Zdar Max
Měl jsem sen ... :(
vencour avatar 30.3.2021 12:01 vencour | skóre: 56 | blog: Tady je Vencourovo | Praha+západní Čechy
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
I tohle (2 tuxové) vypadá hezky. Občas se mi zápisek líbí víc než jindy ... nebo aspoň nějaké obraty.
Ty nejhlubší objevy nečekají nutně za příští hvězdou. Jsou uvnitř nás utkány do vláken, která nás spojují, nás všechny.
Gréta avatar 31.3.2021 12:52 Gréta | skóre: 36 | blog: Grétin blogísek | 🇮🇱==❤️ , 🇵🇸==💩 , 🇪🇺==☭
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
otasomil avatar 30.3.2021 17:19 otasomil | skóre: 39 | blog: puppylinux
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Odpovědět | Sbalit | Link | Blokovat | Admin
Pekne, poucne.

Info o mnozstvi CO2 mi pripomelo mrknout do technickeho slovniku z roku 1956 abych zjistil ze slozeni vzduchu je az do dneska prakticky stejne. Dnesek A tehdejsi udaje:
Kyslik: 20,75%
Dusik: 77.08%
Oxid uhlicity: 0.03%
Ostatni neuvadim pro nadbytecnost a zanedbatelna cisla.
K čemu hudba, která nevede k extázi... Stop MDMA !!! I spam umí být roztomilý
30.3.2021 21:28 Great Gréta
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Příroda: nárůst CO2 o 30% za 70 let

Otasomil: PRaKTicKy stEJné
otasomil avatar 30.3.2021 21:53 otasomil | skóre: 39 | blog: puppylinux
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
JJ je to cca 30% + ovsem v celkove casti procentualniho slozeni vzduchu je CO2 takrka zanedbatelna polozka jak pred 70 lety tak dnes. Jo ekoteroristi reknou narust o 30% a hned tim vydesi celou planetu. Cili kdyz do litru vody naleju cca 0.3 ml slivovice tak mam hned narust alkoholu ve sklenici vody o 100% coz je desive nicmene nic to neznamena.
K čemu hudba, která nevede k extázi... Stop MDMA !!! I spam umí být roztomilý
Jendа avatar 31.3.2021 01:49 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
ovsem v celkove casti procentualniho slozeni vzduchu je CO2 takrka zanedbatelna polozka jak pred 70 lety tak dnes
A z hlediska té sledované aktivity? (absorpce odraženého/vyzářeného IR a z toho vyplývajíví vliv na teplotu a obecně klima)
Cili kdyz do litru vody naleju cca 0.3 ml slivovice tak mam hned narust alkoholu ve sklenici vody o 100% coz je desive nicmene nic to neznamena.
1) O nekonečně %, 2) Když ti pustím do pokoje 0.03% kyanovodíku tak se ti to taky nebude líbit. A přitom jsou to jenom 0.03%!
otasomil avatar 31.3.2021 05:11 otasomil | skóre: 39 | blog: puppylinux
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Kyanovodik je nejjedovatejsi latka co vubec existuje. Zato kdyz si do pokoje privedu slecnu tak za hodinu mi tam vyfuni tolik CO2 ze jeho hladina vzroste o stovky % takze cele to hrani si s tisicinama % CO2 mi zavani ekoterorismem.
K čemu hudba, která nevede k extázi... Stop MDMA !!! I spam umí být roztomilý
Max avatar 31.3.2021 08:59 Max | skóre: 72 | blog: Max_Devaine
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
slecnu tak za hodinu mi tam vyfuni tolik CO2 ze jeho hladina vzroste o stovky %

Ty si ale věříš :D. To u mě za ty dvě minuty nestačí nadejchat CO2 ani pro jednu kytičku :).
Zdar Max
Měl jsem sen ... :(
otasomil avatar 31.3.2021 16:13 otasomil | skóre: 39 | blog: puppylinux
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
To u mě za ty dvě minuty...
Teda to je rychlovka. Musim se vsak omluvit ze jsem se nespravne genderove vyjadril a ze jsem misto slecny mel napsat clovek.
K čemu hudba, která nevede k extázi... Stop MDMA !!! I spam umí být roztomilý
Gréta avatar 31.3.2021 19:39 Gréta | skóre: 36 | blog: Grétin blogísek | 🇮🇱==❤️ , 🇵🇸==💩 , 🇪🇺==☭
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu

přeci ji jako hnedka potom nestrčíš ven zadveře ne :D

Max avatar 31.3.2021 20:17 Max | skóre: 72 | blog: Max_Devaine
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
To ne, je to naopak, za dveře jdu já :D
Zdar Max
Měl jsem sen ... :(
Jendа avatar 31.3.2021 11:01 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Kyanovodik je nejjedovatejsi latka co vubec existuje.
Takže to vypadá, že asi nejde tvrdit „je něčeho jenom 0.03%, nemůže to mít žádný vliv“, že?
Zato kdyz si do pokoje privedu slecnu tak za hodinu mi tam vyfuni tolik CO2 ze jeho hladina vzroste o stovky % takze cele to hrani si s tisicinama % CO2 mi zavani ekoterorismem.
Ale ono přece nejde o to, že by zvýšení CO2 z 270 na současných 420 nebo za pár let predikovaných 500 ppm nějak přímo škodilo člověku (jak se snažíš naznačit na příkladu s místností) ve smyslu dýchání, ale o to, že CO2 absorbuje infračervené záření a tím způsobuje oteplování.

To je strawman, nebo tomu opravdu nerozumíš?
31.3.2021 12:16 Mayhem
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Herr Jenda, jak jste to meril? Jaka mate data, kdyz tvrdite udaje o PPM? A jake byly hodnoty teto veliciny v minulosti? Nebyly nahodou i nekolikanasobne vyssi? Opravdu si myslite, ze tech vasich 420PPM, ktera mate zmerena nevim odkud, jsou antropogenniho puvodu? A i kdyby, je na tom neco spatneho?
Jendа avatar 31.3.2021 12:23 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Chápu správně, že tvrdíš, že ve vzduchu na zemi aktuálně není 420 ppm, že to je konspirace a ve skutečnosti je mnohem míň?

Pak si bohužel nemáme co říct. Hezký den.
31.3.2021 13:38 Mayhem
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Ne, nechapes to spravne. Netvrdim, ze neni 420. Ja osobne to netusim. Zajima mne, jaka mas data pro podlozeni tohoto sveho tvrzeni. Nebo to beres jako dogma?
31.3.2021 15:17 kek
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
*42069 ppm
Gréta avatar 31.3.2021 13:10 Gréta | skóre: 36 | blog: Grétin blogísek | 🇮🇱==❤️ , 🇵🇸==💩 , 🇪🇺==☭
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu

co2 prej teda jako pomáhá maši planetě zachytávat a udržovat teplo. noa díky tomu tady v noci neni taková zima jako třeba na měsíci když tam nesvítí sluníčko. chceš snad ze země mit nevobyvatelnou měsíční pustinu???? :O :O :D ;D

31.3.2021 13:39 Mayhem
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Presne. A diky otepleni klesne spotreba uhli, protoze strejcove nebudou muset tolik nakladat do kotlu, takze vyssi co2 bude mit pozitivni vliv na emise z uhli.
Jendа avatar 31.3.2021 11:06 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
A pedantická:
Kyanovodik je nejjedovatejsi latka co vubec existuje.
V žádném případě, existuje hromada zejména organických látek (např. botulotoxin), které jsou o mnoho řádů jedovatější.
Zato kdyz si do pokoje privedu slecnu tak za hodinu mi tam vyfuni tolik CO2 ze jeho hladina vzroste o stovky % takze cele to hrani si s tisicinama % CO2 mi zavani ekoterorismem.
V tomto okamžiku je už pro dorozumění se v diskuzi zásadní rozlišovat mezi procenty a procentními body, protože pokud jsi v obou případech myslel buď procenta, nebo procentní body, tak jsi napsal naprostý nesmysl.
otasomil avatar 31.3.2021 16:20 otasomil | skóre: 39 | blog: puppylinux
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Estli je ve zduchu neceho "jen nedychatelnyho" 0.03 nebo 0.04% tak se nemame ceho obavat a vse kolem je jen ekoterorismus.

Jeden nejmenovany obchodni retezec "podvadel" ze v prodavane uzenine je 8% masa pritom inspekce zjistila ze je tam jen 6% cili maso tam zkratka neni a je uz uplne jedno jestli 6 nebo 8% kdyz to pes nezere a zakutali pod stul protoze nevi co s tim parkem ma delat.
K čemu hudba, která nevede k extázi... Stop MDMA !!! I spam umí být roztomilý
31.3.2021 16:27 Make Greta Great Again
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
A dokážeš myslet i dál než na konec svýho rypáku?
31.3.2021 17:00 podlesh
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Estli je ve zduchu neceho "jen nedychatelnyho"
Já jsem pro každou srandu, ale tady mi ten vtip nějak uniká. Je to narážka na nějakou hlášku, něco co někdo řekl v televizi, nebo nějaký meme, nebo...?? Nechápu.
otasomil avatar 31.3.2021 20:45 otasomil | skóre: 39 | blog: puppylinux
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Neni to zadna narazka jen to ze za 70 let se zvysilo mnozstvi CO2 cca o 30% a tak mame dnes ve vzduchu misto 0.0300% CO2 0.0407% to je vse. Medialne je narust 30% totalni katastrofa ale prirustku 0.0107% by si nikdo nevsiml, nebylo by to popularni a uz vubec ne alarmujici, ekoteroristi by memeli cim argumentovat protoze opravdu uprimne hodnota 0.0107% neni nic co by vyvolalo jakekoli obavy laicke verejnosti. Vse je jen o tom jak to svetu podate, nic vic. To jestli nas prirustek 0.0107% zabije nebo zpusobi nejake globalni oteplovani je vec dalsi.
K čemu hudba, která nevede k extázi... Stop MDMA !!! I spam umí být roztomilý
1.4.2021 13:22 podlesh
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
To jestli nas prirustek 0.0107% zabije nebo zpusobi nejake globalni oteplovani je vec dalsi.
To je právě to co nechápu - kdy'ž je tohle to "další", tak co je to první?

Asi mi furt uniká na co to má být narážka...
otasomil avatar 1.4.2021 16:54 otasomil | skóre: 39 | blog: puppylinux
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Co je na tom k nepochopeni? 0.0107% nas rozhodne nezabije a ani nezpusobi zadne jine problemy ale 30% to je opravdu katastrofa.
K čemu hudba, která nevede k extázi... Stop MDMA !!! I spam umí být roztomilý
2.4.2021 13:29 podlesh
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
K nepochopení je kdes to vzal. Já jsem nikdy nic takového neslyšel.
Gréta avatar 31.3.2021 19:36 Gréta | skóre: 36 | blog: Grétin blogísek | 🇮🇱==❤️ , 🇵🇸==💩 , 🇪🇺==☭
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu

proto si jako ten co2 rudozelený 'experťy' vybraly protože je to taková duchařina :D ;D tvl blbá vodní pára má víc jak 60% podíl na tom údajným globálním voteplovaní proč se neřeší nějaký vysoušení potoků/rybníků??? toby mělo víc věčí význam než dělání s 0.00000000000000000% něčeho neviditelnýho/nemastnýho/neslanýho. ale tady ňák tak intujitivně cejtíme žeto je jakože uplně pitomej nápad bojovat proti vodě/vodní páře :O ;D

bojovat proti co2 je stejná pitomina akorátže to rudozelený jakoby neviděj nebo vidět nechtěj :O :/

Jendа avatar 31.3.2021 20:14 Jendа | skóre: 78 | blog: Jenda | JO70FB
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Estli je ve zduchu neceho "jen nedychatelnyho" 0.03 nebo 0.04% tak se nemame ceho obavat a vse kolem je jen ekoterorismus.
Ale „ekoteroristi“ přece nebojují proti CO2 kvůli tomu, že zhoršuje lidské dýchání (a v těchto koncentracích opravdu nijak znatelně nezhoršuje), ale kvůli tomu, že otepluje planetu!
Gréta avatar 31.3.2021 13:08 Gréta | skóre: 36 | blog: Grétin blogísek | 🇮🇱==❤️ , 🇵🇸==💩 , 🇪🇺==☭
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu

škoda žeto co2 moc na dělání globálního tepla nefunguje :O :/ si myslim že kdyby to co2 fakt jako fungovalo tak by bylo samo vo sobě uplně supr zelenou technologií na akumulaci ir záření/tepla a mohli by jsme si zněj udělat takovou jakože malilinkatou dysonovu sféru v atmosféře planety :D ;D

xsubway avatar 30.3.2021 23:06 xsubway | skóre: 13 | blog: litera_scripta_manet
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Odpovědět | Sbalit | Link | Blokovat | Admin
"Brno odpálit bum"? Nebudou se pražští cítit ochuzeni? :D
Max avatar 30.3.2021 23:40 Max | skóre: 72 | blog: Max_Devaine
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Naopak, pražští mají to tlačítko, brňáci ne :).
Zdar Max
Měl jsem sen ... :(
Gréta avatar 31.3.2021 12:46 Gréta | skóre: 36 | blog: Grétin blogísek | 🇮🇱==❤️ , 🇵🇸==💩 , 🇪🇺==☭
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu

jestli těto jako uklidní tak praha je na seznamu cílů taky :D :D ;D ;D

Marián Kyral avatar 31.3.2021 08:00 Marián Kyral | skóre: 29 | blog: Sem_Tam | Frýdek-Místek
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Odpovědět | Sbalit | Link | Blokovat | Admin
Mé oči krvácí…
Gréta avatar 31.3.2021 12:47 Gréta | skóre: 36 | blog: Grétin blogísek | 🇮🇱==❤️ , 🇵🇸==💩 , 🇪🇺==☭
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu

si mužeš nastavit nějaký svoje barvičky když seti tydlety jakože nelíběj :D ;D

Marián Kyral avatar 2.4.2021 18:11 Marián Kyral | skóre: 29 | blog: Sem_Tam | Frýdek-Místek
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
To nejsou barvičky. To je zkriplená čeština co se se nedá číst. Si všichni nemusí zrovna brát příklad z Andreje.
1.4.2021 22:44 Helmut
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Tak si kup ochranu očí.
31.3.2021 08:48 j
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Odpovědět | Sbalit | Link | Blokovat | Admin
Koukam ze se ti konecne povedlo zprovoznit IPv5 ;D.

Jinak soudruh programator rika, ze void je fujky fuj, ze by kazda funkce at uz dela cokoli mela neco vracet.

---

Dete s tim guuglem dopice!
Gréta avatar 31.3.2021 12:46 Gréta | skóre: 36 | blog: Grétin blogísek | 🇮🇱==❤️ , 🇵🇸==💩 , 🇪🇺==☭
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu

akorátže když jakože přetěžuju metody poděděný z qt nebo tam mam nějakej danej ukazatel na funkci jako datovej typ definovanej vtom mqttasync.h tak stim toho jako moc nejde dělat :O ;D

a jestli toje fujkyfuj nevim v c++ mužou funkce blejt vyjímky a to je asi jako víc zprávnější způsob jak to jako dělat :O :O

Agent avatar 31.3.2021 18:54 Agent | blog: Life_in_Pieces | HC city
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu
Odpovědět | Sbalit | Link | Blokovat | Admin
Radši nám ukaž tvoje dudlíky :-)
Nevěděl zpočátku, co si počít, jak žít, co dělat, ale brzy se vpravil do role samotáře.
Gréta avatar 31.3.2021 19:17 Gréta | skóre: 36 | blog: Grétin blogísek | 🇮🇱==❤️ , 🇵🇸==💩 , 🇪🇺==☭
Rozbalit Rozbalit vše Re: plazmový mqtt čudliky na plochu

Založit nové vláknoNahoru

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.