Smarthome Central with ArduiTouch Part 3- Actor Device with D1Mini and Relais

Diesmal wollen wir unser SmartHome um ein passives Gerät erweitern, das mit einem Relais dazu geeignet ist auch Steckdosen oder Netzverbraucher zu schalten. Wir verwenden wieder einen D1Mini zusammen mit einem Relais-Modul. Die Schaltung dazu ist sehr einfach.

 

Sketch:

 

//library for WiFi
#include <ESP8266WiFi.h>

//library for the used message protocol
#include "AT_MessageBuffer.h"

//library for ESP Now
extern "C" {   #include <espnow.h>
}

//SSID to search for
#define GW_SSID "ATSmartHome"

//flag to switch debug messages on
#define DEBUG true

#define SEND_TIMEOUT 2000  // 2 Sekunden timeout 

#define INTERVALL 10000 //intervall = 10 seconds

//define channels for the relais
#define CHANNEL_RELAIS 0

//Pins to connect the sensors
#define RELAIS_PIN 2 //GPIO2

//Data structure to save server MAC address
//and a checksum inRTC memory
struct MEMORYDATA {   uint32_t crc32; //checksum for validation   uint8_t mac[6];
};

//MAC address and WLAN channel
MEMORYDATA statinfo;
//time when last sent
uint32_t last_sent = 0; //Timestamp for last sent
uint8_t relais_status = 0; //current status of the relais
String mymac; //own mac address

//we have two message buffers for send and receive
AT_MessageBuffer sendmsg;
AT_MessageBuffer rcvmsg;

//write server MAC and checksum to RTC memory
void UpdateRtcMemory() {     uint32_t crcOfData =AT_CalculateCRC32(((uint8_t*) &statinfo) + 4, sizeof(statinfo) - 4);     statinfo.crc32 = crcOfData;     ESP.rtcUserMemoryWrite(0,(uint32_t*) &statinfo, sizeof(statinfo));
}

//search for the access point
void ScanForSlave() {   bool slaveFound = 0;      int8_t scanResults = WiFi.scanNetworks();   // reset on each scan   if (DEBUG) Serial.println("Scan done");   if (scanResults == 0) {     if (DEBUG) Serial.println("No WiFi devices in AP Mode found");   } else {     if (DEBUG) Serial.print("Found ");      if (DEBUG) Serial.print(scanResults);      if (DEBUG) Serial.println(" devices ");     for (int i = 0; i < scanResults; ++i) {       // Print SSID and RSSI for each device found       String SSID = WiFi.SSID(i);       int32_t RSSI = WiFi.RSSI(i);       int32_t chl = WiFi.channel(i);       String BSSIDstr = WiFi.BSSIDstr(i);       if (DEBUG) {         Serial.print(i + 1);         Serial.print(": ");         Serial.print(SSID);         Serial.print(" /");         Serial.print(chl);         Serial.print(" (");         Serial.print(RSSI);         Serial.print(")");         Serial.println("");       }       delay(10);       // Check if the current device starts with ATSmartHome`       if (SSID == GW_SSID) {         // SSID of interest         if (DEBUG) {           Serial.println("Found a Slave.");           Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println("");         }         int mac[6];         // get the server MAC and save to RTC memory         if ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x%c",  &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] ) ) {           for (int ii = 0; ii < 6; ++ii ) {             statinfo.mac[ii] = (uint8_t) mac[ii];           }           UpdateRtcMemory();         }         slaveFound = 1;         //no more search after AP was found         break;       }     }   }         if (DEBUG) {     if (slaveFound) {       Serial.println("Slave Found, processing..");     } else {       Serial.println("Slave Not Found, trying again.");     }   }   // release RAM   WiFi.scanDelete();
}

void sendData() {   uint8_t buf[100]; //buffer for esp   uint8_t sz = 100;   //clear message buffer   sendmsg.clear();   if (DEBUG) {     Serial.println("Sende "+mymac);   }   sendmsg.setId(mymac);   //add current relais status as a boolean message to the buffer   sendmsg.addSwitchOut(relais_status != 0,CHANNEL_RELAIS);   //fill the buffer and send the content to the control center   if (sendmsg.fillBuffer(buf,&Sz)) esp_now_send(Null, Buf, Sz);   remember the time to calculate interval   last_sent=millis();
}

callback on receive messages from ESP-Now
Void readESPNow(uint8_t *mac_addr, uint8_t *r_data, uint8_t data_len) {   ATDATA PACKET Data;   uint32_t newstatus;   copy received data into receive message buffer   rcvmsg.readBuffer(r_data);   If (mymac.equalsIgnoreCase(rcvmsg.Getid())) {     accept only messages for this device     If (rcvmsg.getPackets() > 0) {       did we get a data packet       Data = rcvmsg.Getdata(0);       If (Debug) {         Serial.Printf("Got data for channel %i value %i ",Data.Channel, Data.Value[0]);       }         If (Data.Channel == CHANNEL_RELAIS) {         if the data were for the right channel set the new status         newstatus = Data.Value[0];         If (newstatus != relais_status) {           if the status has changed we export it to the relais           relais_status = newstatus;           digitalWrite(RELAIS_PIN,relais_status);           If (Debug){             Serial.Printf("Relay status = %i'n",relais_status);           }         }       }     }   }
}

Void Setup() {   If (Debug) {     Serial.Begin(115200);      Serial.println("Start");   }   pinMode(RELAIS_PIN,Output);   digitalWrite(RELAIS_PIN,relais_status);   get local MAC address to use it as device id   mymac = Wifi.macAddress();   If (Debug) {     Serial.Print("My MAC address = ");     Serial.println(mymac);   }   Esp.rtcUserMemoryRead(0, (uint32_t*) &statinfo, Sizeof(statinfo));   If (Debug) Serial.println("RTC Done");   uint32_t crcOfData = AT_CalculateCRC32(((uint8_t*) &statinfo) + 4, Sizeof(statinfo) - 4);   Wifi.Fashion(WIFI_STA); Station mode for esp-now aktor node   If (Debug) Serial.println("WifiMode");   If (statinfo.crc32 != crcOfData) { if checksum different we do not have a valid server MAC     If (Debug) Serial.println("Scan for slave");     ScanForSlave();     for (uint8_t i = 0; i<6;i++) statinfo.mac[i] = gwmac[i];     If (Debug) {       Serial.Printf("This mac: %s, ", Wifi.macAddress().c_str());        Serial.Printf("target mac: %02x%02x%02x%02x%02x%02x%02x", statinfo.Mac[0], statinfo.Mac[1], statinfo.Mac[2], statinfo.Mac[3], statinfo.Mac[4], statinfo.Mac[5]);      }   }   If (esp_now_init() != 0) {     If (Debug) Serial.println("*** ESP_Now init failed");     Esp.restart();   }   ESP Now Controller   Wifi.setAutoConnect(False);   esp_now_set_self_role(3); (ESP_NOW_ROLE_CONTROLLER);   uint8_t Ch = esp_now_get_peer_channel(statinfo.Mac);   If (Debug) Serial.Printf("Channel = %i'r"n",Ch);   initialize Peer data   Int Res = esp_now_add_peer(statinfo.Mac, ESP_NOW_ROLE_CONTROLLER, 1, Null, 0);   If (Res==0) Serial.println("Successful paired");   register callback   esp_now_register_recv_cb(readESPNow); 
}

Void Loop() {   send messages to the control center on a regular base   If ((millis() - last_sent) > Interval) {  interval to send data change this if required     sendData();   }
}

 

 

For the program, the ESP8266Wifi.h and the espnow.h Library for the ESP8266. In addition, the library is ATMessageBuffer for SmartHome.

The SmartHome control panel also needs to be connected to the latest libraries ATMessagebuffer, ATSmartHome And TouchEvent compiled. In the examples of ATSmartHome you will also find sketch above.

After the ESP8266Switch and ATSmartHome programs have been compiled from the examples of the AT_SmartHome library and uploaded to the D1Mini or ArduiTouch, the FileSystem should first be formatted on the SmartHome headquarters, which I changed the data structure of the config file during this update. But this is not too bad as we have not been able to make manual settings in the previous versions.

After a reset of the control panel and the start of the D1Mini, its MAC address should be displayed in the lower blue bar.

A double click on this bar will take us to the registration page.

After double-clicking on Register, the display switches back to the main page and we should see the following image.

If you touch this button briefly, turn on the reais and switch it off again with another short touch. The background color of the button changes from gray to light green.

Of course, you can use both modules sensor and switch at the same time (see cover image).

Have fun trying and experimenting.

Esp-8266Projekte für fortgeschritteneSmart home

6 comments

Jörg Reinisch

Jörg Reinisch

@OGGIN→
Ich weiß ja beim besten Willen nicht was ich noch alles versuchen soll.
Ich habe die Erweiterung des Sketch, so wie du es hier geschrieben hast, auch eingegeben.
Ich habe einen D1 Mini Pro, von der Beschaltung her eigentlich nicht anders.
Nur kann ich beim besten Willen in keinem Fall das zweite Relais ansteuern, obwohl ich es auch auf meiner Anzeige im Display als Switch 1 stehen habe,
Ich kann dir ja gern mal den Sketch zukommen lassen, vielleicht findest du ja den Fehler den ich verzweifelt suche.

Jörg

Jörg

Die ganze Schaltung und Programmierung an sich ist schon wirklich ein wunderbares Spielfeld.
Im Großen und Ganzen macht die Schaltung ja auch genau das was sie eigentlich machen sollte……
eigentlich!?!?
Ich hab nur das Problem dass wenn ich mein Relais auschalten lassen will, diese eingeschaltet wird und genau auch umgekehrt. Ich bin auch schier am Verzweifeln und finde nicht die Stelle an der ich diesen ominösen Umstand umkehren kann…..
Kann mir einer auf die Sprünge helfen?

Oggin

Oggin

Hallo Sven,
ich habe den ESP8266Switch.ino Sketch erweitert für zwei Relais (den Namen Relais habe ich nach Relais1 u. 2 erweitert). Habe den Code Auszugsweise in mehren Teil-Abschnitten des Sketchs kopiert, wie folgt:

//Pins to connect the sensors
#define RELAIS2_PIN 2 //GPIO2 ESP8266-01
#define RELAIS1_PIN 0 //GPIO0 ESP8266-01

// Beide Relais werden invers angesteuert
uint8_t relais1_status = 1; //current status of the relais
uint8_t relais2_status = 1; //current status of the relais

sendData:
sendmsg.addSwitchOut(relais1_status != 0,CHANNEL_RELAIS1);
sendmsg.addSwitchOut(relais2_status != 0,CHANNEL_RELAIS2);

if (data.channel == CHANNEL_RELAIS1) {
//if the data were for the right channel set the new status
newstatus = data.value0;
if (newstatus != relais1_status) {
//if the status has changed we export it to the relais
relais1_status = newstatus;
digitalWrite(RELAIS1_PIN,!(relais1_status));
if (DEBUG){
Serial.printf(“Relais1 status = %i\n”,relais1_status);
}
}
}
if (data.channel == CHANNEL_RELAIS2) {
//if the data were for the right channel set the new status
newstatus = data.value0;
if (newstatus != relais2_status) {
//if the status has changed we export it to the relais
relais2_status = newstatus;
digitalWrite(RELAIS2_PIN,!(relais2_status));
if (DEBUG){
Serial.printf(“Relais2 status = %i\n”,relais2_status);
}
}
}
}
}

Setup:
pinMode(RELAIS1_PIN,OUTPUT);
pinMode(RELAIS2_PIN,OUTPUT);
digitalWrite(RELAIS1_PIN,!(relais1_status));
digitalWrite(RELAIS2_PIN,!( relais2_status));

-——————
Das ist es im Wesentlichen.
Kann Dir den Sketch auch per Mail schicken, dazu brauche ich aber Deine Mail-Adr.
Gruß
Oggin

Sven Hesse

Sven Hesse

Jetzt muss ich einfach mal fragen – entweder habe ich einen Denkfehler oder ich mache etwas falsch.

Man kann doch mit dem D1 Mini auch mehrere Relais steuern …..wie aber bekomme ich die Informationen dazu ( Relais_Channel, Relais_Pin) auch in den Sketch.
Ich habe nun schon so viel probiert, bekomme es aber einfach nicht hin :-(.
Kann mir jemand einen Denkanstoß geben?

Sven Hesse

Sven Hesse

Die Registrierungsseite für neue Geräte (ESP8266/D1 Mini) wird nicht mittels Doppelklick auf den blauen Balken erreicht, sondern indem man lange auf den blauen Balken drückt.

In der SmartHome.ino wird auch ein AP-Passwort initiiert, im Sketch für den D1 Mini jedoch nicht definiert.
Entweder man definiert hier kein AP-Passwort oder initiiert eben eines für die D1-Mini.

Peter Necas

Peter Necas

Zu meinem gestrigen Kommentar betreffend Display bleibt dunkel.
Inzwischen habe ich die Zeilen:
#ifdef ARDUITOUCH0102
digitalWrite(TFT_LED, LOW);
gefunden. Damit ist mein Kommentar gegenstandslos,

Besten Dank,
Peter.

Leave a comment

All comments are moderated before being published