Aktualizacja stanu przekaźnika w aplikacji

User avatar
Duch__
Posts: 2199
Joined: Wed Aug 24, 2016 7:26 pm
Location: Opole
Been thanked: 6 times

Post

Hej.

Mam sobie taki oto soft:

Code: Select all

/*
  Copyright (C) AC SOFTWARE SP. Z O.O.

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#define STATUS_LED_GPIO 2

#include <SuplaDevice.h>
#include <supla/network/esp_wifi.h>
#include <supla/device/status_led.h>
#include <supla/storage/littlefs_config.h>
#include <supla/network/esp_web_server.h>
#include <supla/network/html/device_info.h>
#include <supla/network/html/protocol_parameters.h>
#include <supla/network/html/status_led_parameters.h>
#include <supla/network/html/wifi_parameters.h>
#include <supla/device/supla_ca_cert.h>
#include <supla/control/virtual_relay.h>
#include <supla/storage/eeprom.h>

Supla::Eeprom eeprom;

Supla::ESPWifi wifi;
Supla::LittleFsConfig configSupla;

Supla::Device::StatusLed statusLed(STATUS_LED_GPIO, true); // inverted state
Supla::EspWebServer suplaServer;

Supla::Control::VirtualRelay *vr = nullptr;

// Ustawienia MikroTik
const char* mt_ip = "192.168.1.1";
const int mt_port = 1234;
const char* mt_user = "supla";
const char* mt_pass = "alpus";

bool stan_portu_sfp_aktualny;
bool stan_jaki_powinien_byc;

unsigned long lastcheck_port = 0;


WiFiClient client;

void setup() {
  Serial.begin(115200);

  // HTML www component
  new Supla::Html::DeviceInfo(&SuplaDevice);
  new Supla::Html::WifiParameters;
  new Supla::Html::ProtocolParameters;
  new Supla::Html::StatusLedParameters;

  // Channel #0 Virtual Relay
  vr = new Supla::Control::VirtualRelay();
  vr->setDefaultFunction(SUPLA_CHANNELFNC_POWERSWITCH);
  // Enable state restore after device restart:
  vr->setDefaultStateRestore();

  // configure defualt Supla CA certificate
  SuplaDevice.setSuplaCACert(suplaCACert);
  SuplaDevice.setSupla3rdPartyCACert(supla3rdCACert);

  SuplaDevice.begin();
}

void loop() {
  SuplaDevice.iterate();

  
  if(WiFi.status() == WL_CONNECTED){
    if (millis() - lastcheck_port >= 1000) {
      lastcheck_port = millis();
      checkPort("sfp");
      stan_jaki_powinien_byc = 0;
      if(vr->isOn()){stan_jaki_powinien_byc = 1;} 
    }
  
    if(stan_jaki_powinien_byc == 0 && stan_portu_sfp_aktualny == 1){
      disablePort("sfp");
      Serial.println("DISABLE SFP");
    }

    if(stan_jaki_powinien_byc == 1 && stan_portu_sfp_aktualny == 0){
      enablePort("sfp");
      Serial.println("ENABLE SFP");
    } 
  }
}





// -------------------------------
// Funkcja sprawdzająca stan portu
bool checkPort(const String& iface) {
  if (!mtLogin()) return false;

  //Serial.println("Sprawdzanie stanu portu: " + iface);

  writeWord("/interface/ethernet/print");
  writeWord("=.proplist=name,disabled");
  writeWord("?name");      // <-- bez "="
  writeWord(iface);        // <-- nazwa portu jako osobne słowo
  endSentence();


  

  delay(200);

  bool portEnabled = false;
  while (client.available()) {
    String line = client.readStringUntil(0x00);
    //Serial.println("DEBUG: " + line); // debug całej odpowiedzi
    if (line.indexOf("disabled=") >= 0) {
      portEnabled = line.indexOf("true") < 0; // true → wyłączony, false → włączony
    }
  }

  if(portEnabled == true){
    stan_portu_sfp_aktualny = 1;
  }else{
    stan_portu_sfp_aktualny = 0;
  }
  
  mtLogout();

    if(stan_portu_sfp_aktualny == 1){
      Serial.println("Port SFP jest ENABLE");  
    }
    if(stan_portu_sfp_aktualny == 0){
      Serial.println("Port SFP jest DISABLE");  
    }

  
  return portEnabled;
}





// Flaga stanu portu
unsigned long lastToggle = 0;
// -------------------------------
// Funkcja: wyślij "słowo" do MikroTik API
void writeWord(const String& word) {
  int len = word.length();
  client.write((uint8_t)len);
  client.print(word);
}

// Funkcja: zakończenie sekwencji komendy
void endSentence() {
  client.write((uint8_t)0x00);
}

// -------------------------------
// Funkcja logowania do MikroTik
bool mtLogin() {
  if (!client.connect(mt_ip, mt_port)) {
    Serial.println("❌ Brak połączenia z MikroTik");
    return false;
  }

  // Login i hasło (RouterOS v6/v7 – prosty login)
  writeWord("/login");
  writeWord("=name=" + String(mt_user));
  writeWord("=password=" + String(mt_pass));
  endSentence();

  delay(200);
  while (client.available()) client.read(); // czyszczenie bufora

  //Serial.println("Zalogowano");
  return true;
}

// Funkcja: wylogowanie (zamknięcie sesji)
void mtLogout() {
  if (client.connected()) {
    client.stop();  // zamyka socket
    //Serial.println("Wylogowano (rozłączono)");
  }
}

// -------------------------------
// Funkcja: włączanie portu
void enablePort(const String& iface) {
  if (!mtLogin()) return;
  writeWord("/interface/ethernet/enable");
  writeWord("=numbers=" + iface);
  endSentence();
  Serial.println("Wysłano rozkaz: ENABLE " + iface);
  delay(100);
  mtLogout();
}

// Funkcja: wyłączanie portu
void disablePort(const String& iface) {
  if (!mtLogin()) return;
  writeWord("/interface/ethernet/disable");
  writeWord("=numbers=" + iface);
  endSentence();
  Serial.println("Wysłano rozkaz: DISABLE " + iface);
  delay(100);
  mtLogout();
}
Program ma za zadanie wysyłać rozkaz do Mikrotika włącz port SFP (enablePort("sfp");)/ wyłącz port SFP (disablePort("sfp");)

Funkcja checkPort("sfp") zwraca mi w zmiennej stan_portu_sfp_aktualny to czy port jest włączony czy wyłaczony (1 = włączony, 0 = wyłaczony).

O ile komunikacja wysyłania rozkazów poprzez wirtualny przekaźnik działa w jedną stronę (sterowanie z telefonu), to mam problem z aktualizacją stanów w drugą stronę gdy ręcznie na mikrotiku zmienie ENABLE / DISABLE to chciałbym to odzwierciedlić w apce.

Wiem że muszę użyć opcji vr-TurnOn() i vr-TurnOff(), ale wszystko się rozbija o kierunkowość rozkazu.

Pomoże ktoś?
User avatar
klew
Posts: 13908
Joined: Thu Jun 27, 2019 12:16 pm
Location: Wrocław
Has thanked: 135 times
Been thanked: 137 times

Post

Duch__ wrote: Wed Sep 10, 2025 12:21 pm
Ogólnie powinieneś zapamiętywać poprzedni stan raportowany przez zewnętrzne urządzenie i jeśli się sam zmieni, to vr->turnOn() lub turnOff().
Wtedy stan się poprawi w apce.

Stan czytasz samemu, stan VR też masz w kodzie, więc dość łatwo kilkoma ifami stwierdzić, czy zmienił się samoczynnie stan urządzenia, czy też VR (np. z apki). Wtedy albo aktualizujesz stan VR (j/w), albo wysyłasz polecenie zmieniające stan urządzenia.
Najlepsze suple dla Twojego domu :mrgreen:
User avatar
Duch__
Posts: 2199
Joined: Wed Aug 24, 2016 7:26 pm
Location: Opole
Been thanked: 6 times

Post

A można odczytać jakiś znacznik że rozkaz został wysłany przez telefon / serwer?
User avatar
klew
Posts: 13908
Joined: Thu Jun 27, 2019 12:16 pm
Location: Wrocław
Has thanked: 135 times
Been thanked: 137 times

Post

Duch__ wrote: Wed Sep 10, 2025 12:35 pm A można odczytać jakiś znacznik że rozkaz został wysłany przez telefon / serwer?
Nie, nie ma takiego znacznika.
Ale jeśli zapamiętasz sobie stan VR w jakiejś zmiennej, to jeśli on się zmieni, to zmiana musiała się wykonać z zewnątrz - chyba, że sam w kodzie to przestawiłeś -> ale wtedy wiesz co robisz i dlaczego :)
Najlepsze suple dla Twojego domu :mrgreen:
User avatar
vajera
Posts: 7290
Joined: Wed Oct 31, 2018 7:58 am
Location: Biedrusko
Has thanked: 290 times
Been thanked: 161 times

Post

Duch__ wrote: Wed Sep 10, 2025 12:35 pm A można odczytać jakiś znacznik że rozkaz został wysłany przez telefon / serwer?
Możesz napisać sobie klasę pochodną po VirtualRelay i wtedy nadpisać metody turnOn() i turnOff() albo handleNewValueFromServer().
Bramka Zigbee <=> SUPLA
Więcej informacji tutaj:
https://forum.supla.org/viewforum.php?f=127
FAQ https://forum.supla.org/viewtopic.php?t=17277

Return to “Ogólna dyskusja”