HF Antenne omschakelaar (3)

Dit artikel beschrijft de software voor de ESP32 microcontroller

Om de ESP32 te programmeren heb ik gebruik gemaakt van de Arduino programmeer omgeving. De meeste tutorials die je op internet kunt vinden gaan hier van uit, en ik heb hiermee al wat ervaring opgedaan. Dat was voor mij dus een logische keuze.

Ik gebruik Telegram om commando’s naar de schakelaar te sturen. Er zijn ook andere manieren, maar ik heb voor deze gekozen. Het vereist een aantal stappen, die ik hier niet ga herhalen, aangezien ze op deze site uitstekend worden beschreven:

Microcontrollerslab website

Als je de stappen hebt doorlopen, heb je een bot gereedstaan die je kunt gebruiken om commando’s naar de ESP32 te sturen. Deze kun je afvangen, en in de code gebruiken.

Library definities:

#include "WiFi.h"
#include "SSD1306Wire.h"
#include "time.h"
#include "WiFiClientSecure.h"
#include "UniversalTelegramBot.h"
#include "ArduinoJson.h"
#include "DHT.h"

Definities:

#define BOTtoken "<your BOTtoken"
#define CHAT_ID "<your CHAT_ID>"
#define DHTPIN 25 //defines to which GPIO pin the temp sensor is connected
#define DHTTYPE DHT22 //defines sensor type

Declaratie van constantes en variabelen:

const char* ssid = "<Your SSID>";
const char* password =  "<your router password>";
const char* ntpServer = "pool.ntp.org"; //time server URL
const long gmtOffset_sec = 3600; //we are one hour ahead of gmt (UTC)
const int daylightOffset_sec = 3600;
String hostname = "Antenna-Switch";
unsigned long previousMillis = 0;
unsigned long interval = 30000;
String temperature; //variable for holding measured temperature
String line1; //variable for display line 1
String line2; //variable for display line 2
bool feedBack; //variable for holding status of relay
 
// OLED Display 128x32
SSD1306Wire  display(0x3c, 32, 33);

//setup WiFi client
WiFiClientSecure client;
UniversalTelegramBot bot(BOTtoken, client);

// Checks for new messages every second.
int bot_delay = 1000;
unsigned long lastTimeBotRan;

const int setPin = 12; //GPIO-12
const int resetPin = 13; //GPIO-13
const int fbPin = 14; //GPIO-14
bool setState = LOW; //initial state of output
bool resetState = LOW; //initial state of output 
DHT dht(DHTPIN, DHTTYPE); //initialize temperature measurement sensor

Onderstaand programma wordt één keer bij het opstarten van de controller uitgevoerd, en zet bepaalde zaken in de juiste stand.

void setup() {
  Serial.begin(115200);  //setup serial channel for debugging
  
// Initialize pins and make sure output is off
  pinMode(setPin, OUTPUT); //initialize GPIO pin for switching the relay on
  pinMode(resetPin, OUTPUT); //initialize GPIO pin for switching the relay off
  pinMode(fbPin, INPUT_PULLUP); //initialize GPIO pin for reading the relay position 
  digitalWrite(setPin, setState); //ensure pin is off at start
  digitalWrite(resetPin, resetState); //ensure pin is off at start

// Start Wifi interface and connect
  WiFi.mode(WIFI_STA);
  WiFi.setHostname(hostname.c_str());
  WiFi.begin(ssid, password);
  client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Add root certificate for api.telegram.org
  while (WiFi.status() != WL_CONNECTED) {
    delay(3000);
    Serial.println("Connecting to WiFi..");
  }
  Serial.println("Connected to the WiFi network "your network");
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());

// NTP time init  
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

// OLED display init
  display.init();
  display.clear();

// Give welcome message and start temp measurement
  draw_msg("PA3FQH");
  delay(3000);
  dht.begin();
}

Onderstaande functie vangt berichten die door Telegram zijn gestuurd op en interpreteert deze. Op basis van de inhoud van het bericht zal hij e.e.a. doen:
– Relais setten of resetten
– De stand van het relais terugsturen naar Telegram
– De locale tijd terugsturen naar Telegram
– De gemeten temperatuur terugsturen naar Telegram

void handleNewMessages(int numNewMessages) {
  Serial.println("Handling New Message");
  Serial.println(String(numNewMessages));

  for (int i=0; i<numNewMessages; i++) {
    // Chat id of the requester
    String chat_id = String(bot.messages[i].chat_id);
    if (chat_id != CHAT_ID){
      bot.sendMessage(chat_id, "Unauthorized user", "");
      continue;
    }
    
    // Print the received message
    String user_text = bot.messages[i].text;
    Serial.println(user_text);

    String your_name = bot.messages[i].from_name;
    if (user_text == "/temp") {
      bot.sendMessage(chat_id,temperature,"");
      } 
    if (user_text == "/start") {
      
      String welcome = "Welkom, " + your_name + ".\n";
      welcome += "Gebruik onderstaande commando's om de antenne schakelaar te bedienen:\n\n";
      welcome += "Stuur /tuinhuis om de antenne met het tuinhuis te verbinden \n";
      welcome += "Stuur /zolder om de antenne met de zolder te verbinden \n";
      welcome += "Stuur /status om de huidige status op te vragen \n";
      welcome += "Stuur /time om de huidige tijd op te vragen \n";
      welcome += "Stuur /temp om de huidige temperatuur op te vragen \n\n";
            if (digitalRead(fbPin)){
        welcome += "Antenne is op dit moment met de zolder verbonden \n";
      }
      else{
        welcome += "Antenne is op dit moment met het tuinhuis verbonden \n";
      }
      bot.sendMessage(chat_id, welcome, "");
    }

    if (user_text == "/tuinhuis") {
      bot.sendMessage(chat_id, "Antenne verbinden met het tuinhuis", "");
      digitalWrite(setPin, HIGH);
      delay(500);
      digitalWrite(setPin, LOW);
    }
    
    if (user_text == "/zolder") {
     bot.sendMessage(chat_id, "Antenne verbinden met de zolder", "");
     digitalWrite(resetPin, HIGH);
     delay(500);
     digitalWrite(resetPin, LOW);
    }
    
    if (user_text == "/status") {
      if (digitalRead(fbPin)){
        bot.sendMessage(chat_id, "Antenne is met de zolder verbonden", "");
      }
      else{
        bot.sendMessage(chat_id, "Antenne is met het tuinhuis verbonden", "");
      }
    }
    if (user_text == "/time") {
      struct tm timeinfo2;
          if (getLocalTime(&timeinfo2)) {
            char time_str2[16];
            strftime(time_str2, 16, "%H:%M:%S", &timeinfo2);
            bot.sendMessage(chat_id, "De tijd is " + String (time_str2),"");
            }  
      }
    }
    
}

Onderstaande functie schrijft data naar het OLED display. Dit wordt eveneens 1 x per seconde uitgevoerd vanuit het hoofdprogramma.

void draw_all(){
  display.clear();
  display.setFont(ArialMT_Plain_24);
  display.setTextAlignment(TEXT_ALIGN_CENTER);
  display.drawString(display.getWidth()/2, 0, temperature);
  display.drawString(display.getWidth()/2, 32, line2);
  display.display();
  }

Hieronder tenslotte het hoofdprogramma (loop) dat cyclisch doorlopen wordt. De functies worden uitgevoerd door een executer die zorgt dat deze één keer per seconde worden uitgevoerd. (waarde van variabele bot_delay).

Als de functies zijn afgehandeld checkt een stukje code of de WiFi verbinding nog actief is. Als deze >30 seconden (variabele interval) niet actief is wordt de verbinding verbroken en opnieuw opgebouwd.

void loop() { 
    //This part checks every <bot_delay> milliseconds for a new message
    if (millis() > lastTimeBotRan + bot_delay)  {
    int numNewMessages = bot.getUpdates(bot.last_message_received + 1);

    while(numNewMessages) {
      Serial.println("Got Response!");
      handleNewMessages(numNewMessages);
      numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    }
    //this part reads the DHT22 for temperature
    float t = dht.readTemperature();
    temperature = String(t,1) + " C "; //format temperature to string

    //this part checks the position of the relay
    feedBack = digitalRead (fbPin);
    if (feedBack == HIGH){
      line2 = "ZOLDER";
    }
    else{
      line2 = "TUINHUIS";
    }
    //Write the data to the OLED display
    //first line: temperature
    //second line: feedback (ZOLDER or TUINHUIS)
    draw_all();

    //this fixes current time to define next execution
    lastTimeBotRan = millis();
  }

  // if WiFi is down, try reconnecting
    unsigned long currentMillis = millis();
    if ((WiFi.status() != WL_CONNECTED) && (currentMillis - previousMillis >=interval)) {
    Serial.print(millis());
    Serial.println("Reconnecting to WiFi...");
    WiFi.disconnect();
    WiFi.reconnect();
    previousMillis = currentMillis;
   }
 }

Het hierboven getoonde programma is natuurlijk geschreven voor mijn doel: het sturen van een coax relais. Maar je kunt het ding ook prima voor andere zaken gebruiken, bijvoorbeeld voor het op afstand aan of uitzetten van een vijverpomp of zo. Het is vrij eenvoudig om de teksten voor de telegram bot aan te passen en nieuwe commando’s te verzinnen.

Bij mij ziet de telegram interface er zo uit: