IOT SYSTEM FULL SYSTEM UBUNTU C++ C PYTHON Qt BUID ALL SYSTEM + MOBILE APP

GİTHUB:

https://github.com/tarnetintern/ciftlikOtomasyon

https://github.com/flavves/BTU-SMRT-HOME

This project has a 3 part 

  • WEB API
  • MOBILE APP
  • NODEMCU ESP-32S V1.1 & ARDUINO

WEB API

Let’s build together

required libraries

  • Flask
  • json
  • os

Environment

  • Ubuntu 22 server

We need to add 2 method POST & GET 

Build POST method

from flask import Flask, request, jsonify
from flask_httpauth import HTTPBasicAuth

import json
import os

app = Flask(__name__)
auth = HTTPBasicAuth()

users = {
    "user1": "pass",
    "user2":"pass"
}

@auth.verify_password
def verify_password(username, password):
    if username in users and users[username] == password:
        return username

@app.route('/webhook', methods=['POST'])
@auth.login_required
def webhook():
    # İstek içeriğini JSON olarak al
    data = request.json

    # Gelen veriyi işle (Örneğin, basitçe yazdır)
    #print("Alınan Veri:", data)
    # JSON dosyasını oku veya yoksa yeni bir sözlük oluştur
    if os.path.exists('data.json'):
        with open('data.json', 'r') as file:
            file_data = json.load(file)
    else:
        file_data = {}

    # Veriyi güncelle veya ekle
    for key, value in data.items():
        file_data[key] = value

    # Güncellenmiş veriyi dosyaya yaz
    with open('data.json', 'w') as file:
        json.dump(file_data, file, indent=4)

    # Başarılı bir yanıt döndür
    return jsonify({"message": "Veri basarıyla alindi",
                    "data":data}), 200

Build GET method



@app.route('/todo', methods=['GET'])
@auth.login_required
def todo():
    if os.path.exists('data.json'):
        with open('data.json', 'r') as file:
            data = json.load(file)
    else:
        data = {"error": "Veri bulunamadı."}

    return jsonify(data), 200

#
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=7171)

Then we need to start our server this code

open terminal and write this command

nano startWebhook.sh
#then write
cd path/yur/pyfile
python3 pythoncode.py
# press ctrl+x and y
#I recommend VS Code for ssh server.
sudo chmod +x start.sh
screen -S my_session
nohup ./start.sh &
#then control 
ps aux | grep python
#if you want to kill your script 
kill <your scripts code>

Server is okay now we need to build an application.

MOBILE APP

If you know C++ and Qt you can continue this part and build your mobile app. If you don’t know, you can use the telegram api. I wrote example code for this but it needs to be upgraded.

Telegram code ! This code is not finished and integrated ! Please wait my update or update this code!

from telegram import Update
from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes
import threading
import time

import requests

import time

import requests
from datetime import datetime
global app

try:
    with open ("evIsiklar1.txt","r") as dosya:
        deneme=dosya.readline()
    dosya.close()
except:
    with open ("evIsiklar1.txt","w") as dosya:
        dosya.write("")
    dosya.close()

try:
    with open ("evAdminleri.txt","r") as dosya:
        deneme=dosya.readline()
    dosya.close()
except:
    with open ("evAdminleri.txt","w") as dosya:
        dosya.write("")
    dosya.close()

try:
    with open ("evGorevleri.txt","r") as dosya:
        deneme=dosya.readline()
    dosya.close()
except:
    with open ("evGorevleri.txt","w") as dosya:
        dosya.write("")
    dosya.close()


async def chatidal(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    chat_id = update.effective_user.id
    await update.message.reply_text(chat_id)

async def adminkaydiyap(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: 
    msg=update.message.text.replace("/a ","")
    try:
        userId=msg.split(" ")[1]
        sifre=msg.split(" ")[0]
        if sifre=="pass":
            #burası sadece belirli bir kullanici olduğunda ççalışacak 
            with open ("evAdminleri.txt","r") as dosya:
                idler=dosya.readline()
            dosya.close()
            idler=idler.split(";")
            if str(userId) in idler:
                await update.message.reply_text(f'Bu kullanıcı zaten kaydedildi!')
            else:    
                with open ("evAdminleri.txt","a") as dosya:
                    dosya.write(str(userId)+";")
                dosya.close()
                
                try:       
                    await update.message.reply_text(f'Kaydedilen kullanıcı ID: {userId}')
                except:
                    await update.message.reply_text(f'Kayıt Başarısız kullanıcı ID: {userId}')
        else:
            await update.message.reply_text("sifre yanlış")
    except:
        await update.message.reply_text("ornek format /a şifre userId")



async def gorevOlustur(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    gelenUserId=str(update.effective_user.id)
    gelenMesaj=update.message.text
    if gelenMesaj=="/go":
        await update.message.reply_text("ornek format /go ışıkları kapat")
    else:    
        gelenMesaj=gelenMesaj.replace("/go ","")
        with open ("evAdminleri.txt","r") as dosya:
                idler=dosya.readline()
                dosya.close()
                idler=idler.split(";")
                donecekListe=""
                if gelenUserId in idler:
                    print("kullanici kayitli gorev ekleyebilir")
                    with open ("evGorevleri.txt","a") as dosya:
                                dosya.write(gelenMesaj+"\n")
                    dosya.close()
                    await update.message.reply_text("Gorev başarıyla eklendi")
        

async def isiklar(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    gelenUserId=str(update.effective_user.id)
    gelenMesaj=update.message.text
    if gelenMesaj=="/isiklar1":
        await update.message.reply_text("ornek format /isiklar1 1 <ışıkları 1 açar 0 kapatır>")
    else: 
        gelenMesaj=gelenMesaj.replace("/isiklar1 ","")
        with open ("evAdminleri.txt","r") as dosya:
                idler=dosya.readline()
                dosya.close()
                idler=idler.split(";")
                donecekListe=""
                if gelenUserId in idler:
                    print("ışıklar görevi geldi")
                    with open ("evIsiklar1.txt","w") as dosya:
                        dosya.write(gelenMesaj)
                    dosya.close()
                    await update.message.reply_text("ışıkların durumu: %s"%str(gelenMesaj))

        pass



app = ApplicationBuilder().token("token").build()

#app.add_handler(CommandHandler("hello", hello))
app.add_handler(CommandHandler("chatidal", chatidal))
app.add_handler(CommandHandler("a", adminkaydiyap))
app.add_handler(CommandHandler("go", gorevOlustur))
app.add_handler(CommandHandler("isiklar1", isiklar))

app.run_polling()

Let’s build together

required

Environment

  • Windows & MAC & Linux & Android

evkontrolpaneli.h

#ifndef EVKONTROLPANELI_H
#define EVKONTROLPANELI_H
#include <QApplication>
#include <QTimer>
#include <QElapsedTimer>
#include <QMap>
#include <QSet>
#include <QMetaMethod>
#include <QMetaObject>
#include <QGuiApplication>
#include <QQuickItem>

#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QFile>
#include <QUrl>

#include <QJsonDocument>
#include <QJsonObject>

class EvKontrolPaneli :public QObject
{

    Q_OBJECT

public:

    EvKontrolPaneli(QObject* parent = nullptr);
    ~EvKontrolPaneli();

    Q_INVOKABLE bool baglanAuth(QString url,QString port,QString kullaniciAdi,QString sifre);
    Q_INVOKABLE bool baglan(QString url,QString port);

    Q_INVOKABLE bool baglantiyiKes();
    Q_INVOKABLE bool baglantiyiKesAuth();

    Q_INVOKABLE bool baglantiyiKontrolEt();
    Q_INVOKABLE bool baglantiyiKontrolEtAuth();

    Q_INVOKABLE bool postData(QString url,QString jsonData);
    Q_INVOKABLE bool postDataAuth(QString url,QString jsonData,QString kullaniciAdi,QString sifre);
    bool getData(QString url);




    void handleApiResponse(QNetworkReply *reply);
    void handleApiResponseAuth(QNetworkReply *reply);

private slots:
    void performGetRequest();  // Yeni slot

private:
    QNetworkAccessManager *manager;
    QNetworkAccessManager *managerAuth;
    QTimer *timer;             // QTimer nesnesi
    QString requestUrl="http://<apiurl>/todo";        // GET isteği yapılacak URL

signals:
    void apiResponseReceived(QString response,int statusCode);

};

#endif // EVKONTROLPANELI_H

evkontrolpaneli.cpp

#include "evkontrolpaneli.h"


EvKontrolPaneli::EvKontrolPaneli(QObject *parent) : QObject(parent)
    ,manager (new QNetworkAccessManager(this))
    ,managerAuth (new QNetworkAccessManager(this))
    ,timer(new QTimer(this))

{
    connect(manager, &QNetworkAccessManager::finished, this, &EvKontrolPaneli::handleApiResponse);

    // Timer'ı ayarlayın ve performGetRequest slot'una bağlayın
    //timer->setInterval(10000); // 10 saniye
    //connect(timer, &QTimer::timeout, this, &EvKontrolPaneli::performGetRequest);
    //timer->start();
}

EvKontrolPaneli::~EvKontrolPaneli()
{
    delete manager;
    delete managerAuth;
    delete timer;

}

void EvKontrolPaneli::performGetRequest()
{

    getData(requestUrl); // Burada URL'nizi belirtin
}

bool EvKontrolPaneli::getData(QString url)
{
    QUrl serviceUrl(url);
    QNetworkRequest request(serviceUrl);

    // GET isteğini başlat
    manager->get(request);

    return true;
}
bool EvKontrolPaneli::baglanAuth(QString url, QString port, QString kullaniciAdi, QString sifre)
{
    return true;

}

bool EvKontrolPaneli::baglan(QString url, QString port)
{
    return true;
}

bool EvKontrolPaneli::baglantiyiKes()
{
    return true;
}

bool EvKontrolPaneli::baglantiyiKesAuth()
{
    return true;
}

bool EvKontrolPaneli::baglantiyiKontrolEt()
{
    return true;
}

bool EvKontrolPaneli::baglantiyiKontrolEtAuth()
{
    return true;
}

bool EvKontrolPaneli::postData(QString url, QString jsonData)
{
    QUrl serviceUrl = QUrl(url);
    QNetworkRequest request(serviceUrl);

    // HTTP Header ayarları
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

    // JSON verisini QJsonDocument nesnesine dönüştürme
    QJsonDocument doc = QJsonDocument::fromJson(jsonData.toUtf8());

    // POST isteğini gönderme
    manager->post(request, doc.toJson());

    return true;
}

bool EvKontrolPaneli::postDataAuth(QString url, QString jsonData, QString kullaniciAdi, QString sifre)
{
    QUrl serviceUrl = QUrl(url);
    QNetworkRequest request(serviceUrl);

    // HTTP Header ayarları
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

    // Basic Auth için kullanıcı adı ve şifreyi Base64 ile kodlama
    QByteArray auth = kullaniciAdi.toUtf8() + ":" + sifre.toUtf8();
    auth = "Basic " + auth.toBase64();
    request.setRawHeader("Authorization", auth);

    // JSON verisini QJsonDocument nesnesine dönüştürme
    QJsonDocument doc = QJsonDocument::fromJson(jsonData.toUtf8());

    // POST isteğini gönderme
    manager->post(request, doc.toJson());

    return true;
}

void EvKontrolPaneli::handleApiResponse(QNetworkReply *reply)
{
    QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
    if (reply->error() == QNetworkReply::NoError) {

        // İstek başarılı, yanıtı oku
        QByteArray responseData = reply->readAll();
        QString responseString(responseData);

        // Yanıtı konsola yazdır veya gerektiği şekilde işle
        qDebug() << "Sunucu Yanıtı:" << responseString;
        emit apiResponseReceived(responseString, statusCode.toInt());
    } else {
        // Bir hata oluştu, hata mesajını yazdır
        qDebug() << "Hata:" << reply->errorString();
        emit apiResponseReceived("responseString", statusCode.toInt());
    }

    reply->deleteLater();
}

void EvKontrolPaneli::handleApiResponseAuth(QNetworkReply *reply)
{

}

evKontrolPaneli.qml

import QtQuick 2.15
import COtomasyon.evControl 1.0

import QtQuick.Controls             2.4
import QtQuick.Dialogs              1.3
import QtQuick.Layouts              1.11
import QtQuick.Window 2.15
import COtomasyon.ScreenToolsController 1.0

import COtomasyon.Ayarlar 1.0

Item {
    property double defaultSpacing: screen.desktopAvailableWidth/40
    property double defaultWidth: mainWindow.width
    property double defaultHeight: mainWindow.height
    property bool tinyScreen : Screen.desktopAvailableWidth < 700
    property var verilerListesi:Ayarlar.ayarlarSayfasiVerileriGetir()
    property bool verilerListesiHazir:verilerListesi.length>0

    property string apiUrl: verilerListesiHazir ? verilerListesi[0]:""
    property string username: verilerListesiHazir ? verilerListesi[1]:""
    property string password: verilerListesiHazir ? verilerListesi[2]:""

    property int    defaultFontPixelWidth: tinyScreen ? 10:20
    property int    defaultFontPixelHeight: tinyScreen ? 5:10
    property int    largeFontPointSize: 30

    ListModel {
        id: lightsModel

        ListElement { name: "Isiklar 1" }
        ListElement { name: "Isiklar 2" }
        ListElement { name: "Isiklar 3" }
        ListElement { name: "Isiklar 4" }
        ListElement { name: "Alarm 1" }
        ListElement { name: "Alarm 2" }
        ListElement { name: "Role 1" }
        ListElement { name: "Role 2" }
        ListElement { name: "Role 3" }
        // Daha fazla ışık eklemek isterseniz ListElement ekleyebilirsiniz
    }

    ScrollView {
        anchors.fill: parent
        anchors.centerIn: parent
        clip: true


        GridLayout {
            id: gridLayout
            columns: 1
            columnSpacing: defaultFontPixelWidth
            rowSpacing: defaultSpacing

            Repeater {
                model: lightsModel

                Item {
                    width: gridLayout.width
                    height: childrenRect.height

                    GridLayout {
                        columns: 4
                        columnSpacing: defaultFontPixelWidth
                        rowSpacing: defaultSpacing

                        Text {
                            color: "#3cd731"
                            text: model.name
                            font.bold: true
                            font.pointSize: 12
                        }

                        Button {
                            text: "aç"
                            onClicked: {
                                var url = apiUrl+"webhook";
                                var json = JSON.stringify({ [model.name]: "1" });
                                //EvControl.postData(url, json)
                                EvControl.postDataAuth(url,json,username,password)
                            }
                        }

                        Button {
                            text: "kapat"
                            onClicked: {
                                var url = apiUrl+"webhook";
                                var json = JSON.stringify({ [model.name]: "0" });
                                //EvControl.postData(url, json)
                                EvControl.postDataAuth(url,json,username,password)
                            }
                        }

                        Text {
                            id: sonucYazisi
                            color: "#3cd731"
                            text: qsTr("Sonuç Yazısı")
                            font.bold: true
                            font.pointSize: 12
                        }
                    }

                    Connections {
                        target: EvControl
                        onApiResponseReceived: {

                            if (statusCode===200) {
                                //console.log(JSON.parse(response)["data"][model.name])
                                if (JSON.parse(response)["data"][model.name] === "1")
                                    sonucYazisi.text = "Açık"
                                else if (JSON.parse(response)["data"][model.name] === "0")
                                    sonucYazisi.text = "Kapalı"
                            }

                        }
                    }
                }
            }
        }
    }

    Component.onCompleted: {
        //EvControl.baglan("","")

    }
    focus: true  // Odağı etkinleştirir

    Keys.onBackPressed: {
        console.log("Geri tuşuna basıldı");
        // Geri tuşuna basıldığında yapılacak işlemler
    }



}

-

Those are a just code you need to be build this project or you can my base app project on github

Project photos

Example 1

NODEMCU ESP-32S V1.1 & ARDUINO

Arduino Code <updated 25.12.2023>

#include <Keypad.h>

const byte ROWS = 4; 
const byte COLS = 4; 

char hexaKeys[ROWS][COLS] = {
  {'*', '0', '#', 'D'},
  {'7', '8', '9', 'C'},
  {'4', '5', '6', 'B'},
  {'1', '2', '3', 'A'}
    
};
byte rowPins[ROWS] = {9, 8, 7, 6}; 
byte colPins[COLS] = {5, 4, 3, 2}; 

Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

const int role1Pin = 11; // Role 1 için pin numarası
const int role2Pin = 12; // Role 2 için pin numarası
const int role3Pin = 13; // Role 1 için pin numarası
const int sifrePin = 10; // Role 1 için pin numarası
// Diğer röleler için benzer şekilde pin tanımlamaları yapabilirsiniz
String inputBuffer = "";
String gelenSifre="";
String defaultSifre="1220";
char customKey;

bool SifreYoneticisi(char customKey){
    gelenSifre+=customKey;
    int uzunluk = gelenSifre.length(); // 
    if(uzunluk>3){
      if(gelenSifre==defaultSifre){
        Serial.println("Sifre Dogru");
        digitalWrite(sifrePin,HIGH);
        gelenSifre="";
        
        return true;
      }
      else{
        Serial.println("Sifre Yanlis");
        gelenSifre="";
        digitalWrite(sifrePin,LOW);
        return false;
      }
      gelenSifre="";
      
    }
    else{
      digitalWrite(sifrePin,LOW);
      return false;
    } 
}

void setup() {
  Serial.begin(115200);
 
  pinMode(role1Pin, OUTPUT);
  pinMode(role2Pin, OUTPUT);
  pinMode(role3Pin, OUTPUT);
  pinMode(sifrePin, OUTPUT);

  // Diğer pinler için de pinMode ayarları
}

void loop() {

  customKey = customKeypad.getKey();
  if (customKey){
    digitalWrite(sifrePin,HIGH);
    delay(100);
    digitalWrite(sifrePin,LOW);
    SifreYoneticisi(customKey); 
    // USE HERE 74hc04 
  }
  
    while (Serial.available() > 0) {
    char incomingByte = Serial.read();
    if (incomingByte == '<') {
      inputBuffer = ""; // Yeni komut başladı, tamponu temizle
    } else if (incomingByte == '>') {
      processCommand(inputBuffer); // Komut tamamlandı, işle
    } else {
      inputBuffer += incomingByte; // Gelen veriyi tampona ekle
    }
  }
}

void processCommand(String command) {
 
  if  (command.startsWith("Role 1")) {
    digitalWrite(role1Pin, command.endsWith("HIGH") ? HIGH : LOW);
  }
  else if  (command.startsWith("Role 2")) {
    digitalWrite(role2Pin, command.endsWith("HIGH") ? HIGH : LOW);
  }
  else if  (command.startsWith("Role 3")) {
    digitalWrite(role3Pin, command.endsWith("HIGH") ? HIGH : LOW);
  }

  // Burada gelen komutu ayrıştırıp ilgili aksiyonları yapın
  // Örneğin, komut "Role1:1" ise, Role1 pinini HIGH yap
}

Nodemcu Code <updated 25.12.2023>

#include <Base64.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
const char* ssid = "<ssid>";//"";     // WiFi SSID'nizi girin
const char* password = "<pass>>";//""; // WiFi şifrenizi girin
//

void setup() {
  Serial.begin(115200);     // Seri iletişim başlatılıyor
  Serial.flush();
  Serial.println("Merhaba"); // Mesajı gönder
  WiFi.begin(ssid, password); // WiFi ağına bağlan
  pinMode(18, OUTPUT); // Pin'i çıkış olarak ayarla
  pinMode(19, OUTPUT);
  pinMode(21, OUTPUT);
  pinMode(22, OUTPUT);
  pinMode(16, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(17, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(0, OUTPUT);
  Serial.println("Merhaba"); // Mesajı gönder
  while (WiFi.status() != WL_CONNECTED) { // WiFi'a bağlanana kadar döngü
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }

  Serial.println("Connected to WiFi");
  
  
}
void sendCommand(const char* command, int pin, const char* value) {
  if (pin != -1) {
    Serial.print("<"); // Başlangıç biti
    Serial.print(command); // Komut
    Serial.print(value); // Değer
    Serial.println(">"); // Bitiş biti
    digitalWrite(pin, strcmp(value, "1") == 0 ? HIGH : LOW);
  }
}

bool sistemleriKontrolEt(DynamicJsonDocument& doc) {
    for (JsonPair p : doc.as<JsonObject>()) {
        const char* key = p.key().c_str(); // JSON anahtarını al
        const char* value = p.value();     // JSON değerini al

        // Anahtar değerlerine göre GPIO pin numaralarını belirle
        int pin = -1;
        if (strcmp(key, "Isiklar 1") == 0) {
            pin = 18;
        } else if (strcmp(key, "Isiklar 2") == 0) {
            pin = 19;
        }else if (strcmp(key, "Isiklar 3") == 0) {
            pin = 21;
        }else if (strcmp(key, "Isiklar 4") == 0) {
            pin = 4;
        }else if (strcmp(key, "Alarm 1") == 0) {
            pin = 0;
        }else if (strcmp(key, "Alarm 2") == 0) {
            pin = 22;
        }else if (strcmp(key, "Role 1") == 0) {
            pin = 5;
        }else if (strcmp(key, "Role 2") == 0) {
            pin = 17;
        }else if (strcmp(key, "Role 3") == 0) {
            pin = 16;
        }
        // Diğer anahtarlar için benzer ifadeler eklenebilir

        if (pin != -1) {
            // "1" ise pin'i HIGH yap, "0" ise LOW yap
            if (strcmp(value, "1") == 0) {
                //Serial.print(key); Serial.println(" -> HIGH");
                sendCommand(key,pin,"HIGH");
                //digitalWrite(pin, HIGH);
            } else if (strcmp(value, "0") == 0) {
                //Serial.print(key); Serial.println(" -> LOW");
                sendCommand(key,pin,"LOW");
                //digitalWrite(pin, LOW);
            }
        }
    }
    return true;
}


void loop() {
  if(WiFi.status() == WL_CONNECTED) { // WiFi'a bağlıysa
    HTTPClient http; // HTTPClient nesnesi oluştur
    String auth = "<username:pass>"; // Kullanıcı adınız ve şifrenizi girin
    auth = base64::encode(auth);

    http.begin("<api>"); // Webhook URL'nizi girin
    http.addHeader("Authorization", "Basic " + auth);
    int httpCode = http.GET(); // HTTP GET isteği yap

    if (httpCode > 0) { // HTTP isteği başarılı mı kontrol et
      String response = http.getString(); // Sunucudan gelen yanıtı al
        //Serial.println(response);
        DynamicJsonDocument doc(1024);
        deserializeJson(doc, response);
        sistemleriKontrolEt(doc);
  
    } else {
      Serial.println("Error on HTTP request");
    }

    http.end(); // HTTPClient nesnesini kapat
  } else {
    Serial.println("WiFi not connected");
  }
  
  delay(1000); // Her 10 saniyede bir bu işlemi tekrarla
}

—-

NodeMCU & ARDUINO communicate with serial comminacition. MCU send bytes with start

Bir yanıt yazın