ich brauche eine technische Unterstützung!
Für ein Projekt habe ich zwei räumlich getrennte Nanos (gleicher Raum, ca. 5m Entfernung, kein Sichtkontakt) die jeweils über ein Relais eine Leuchte schalten.
Diese bleiben unterschiedlich lange an und auch aus (Sekundenbereich). Also ein unregelmäßiges blinken.
Nun möchte ich, das dieses unregelmäßige blinken zwischen den beiden Instanzen gekoppelt wird. Heißt, ich möchte nach beispielsweise 40 verschieden, unsynchronen Blinken, das beide Lampen synchron an gehen. Ein Loop besteht einfach aus ca. 80 HIGH - delay - LOW - delay Blöcken und dauert ca 20 Minuten.
Ich bin ein ziemlicher Laie, darum erstmal die Frage, wie koppel ich die beiden technisch am sinnvollsten und vor allem einfachsten? (vllt 433 MHZ Modul)
Und wäre es genau genug, wenn ich beide Arduinos einfach nur am Anfang des Loops synchroniesieren würde?
@ikaruga
Auch solltest du mal definieren, was du unter synchron verstehst.
Auch wenn beide Nanos einen 16MHz Resonator haben, laufen die noch lange nicht Synchron. Es gibt da schon Abweichungen die nicht unerheblich sind. Synchron bekommst du die, wenn sie aus einer Taktquelle gespeist werden.
Wenn du die mit 433MHz verbinden willst, wird das sicher nicht synchron, du hast immer eine gewisse Verschiebung drin.
Also in meinem Fall würde ich maximal 100ms Versatz als ausreichend Synchron ansehen.
Sollen halt mehrere Tage durchlaufen.
Die Nanos habe ich noch da gehabt und zum Testen reicht es mir. Aber ja, bevor ich mir zwei WLAN Shilds kaufe, würde ich wahrscheinlich zwei ESPs kaufen. Danke für den Link!
Drähte würde ich vermeiden wollen, da ich diese, wenn nicht auf dem kurzen Weg verlegt werden, also durch den Raum, ca. 20 m lang sein müssten. Aber angenommen, ich finde einen cleveren Weg den Draht zu verstecken, wäre dann die serielle Kommunikation der beiden Arduinos eine Möglichkeit?
Weil ich keine Leitung legen will wenn es auch anders möglich ist.
Aber es stimmt wohl, wenn ich Kabel legen würde, könnte ich es auch nur mit einem MC machen.
Allerdings möchte ich, aus verschiedenen, nicht unbedingt technischen Gründen, keine Kabel zwischen den Geräten verlegen.
In der Zwischenzeit könnte ich mir eine Verbindung mit zwei ESP8266 vorstellen (wahrscheinlich direkt zwei NodeMCU, da ich diese auch nach Ende dieses Projekts gut weiter verwenden kann).
Einen könnte man doch dann einen als Accesspoint laufen lassen der den anderen einfach die Befehle zukommen lässt?! (Wie das auch immer funktionieren mag, das ist dann für mich absolutes Neuland.)
man kann das mit "klassischem WLAN" machen. Speziell für ESP8266 oder ESP32 gibt es noch eine weitere Möglichkeit: ESP-NOW.
Das ist ein speziell vom Hersteller der ESP8266 / ESP32 chips entwickeltes Protokoll mit dem ESP8266/ESP32-boards miteinander wireless Daten senden/empfangen können.
Wenn du die beiden Boards mit Netzteil betreibst ist es ziemlich egal ob man nun "klassisches WLAN" und UDP oder ESP-NOW zum Daten senden/empfangen nimmt. (Mit eingeschaltetem WLAN zieht der Mirocontroller 80 mA während des Sendens 300 mA.)
Wenn ein ESP als AP läuft dann ist UDP ein bißchen einfacher weil man weniger Zeilen Code braucht als bei ESP-NOW
Wenn du es per ESP machen willst:
board-Unterstützung installieren
dann frage nach einem geeigneten Demo-Sketch dafür. Es ist wie immer: es gibt eine Menge schlecht dokumentierten Code und wenig gut dokumentierten Code der die Fehlersuche vereinfacht.
Sicher nicht die einfachste. Der eine blinkt an dem Draht (im Sekundentakt), der andere weiß dadurch, wann eine Sekunde anfängt und kann sich synchronisieren, wenn er will.
Das ist auf 20m störunempfindlicher als TTL Serial.
Evtl. kann man mit ein wenig Draht ja doch Sichtkontakt zwischen einer IR-LED und einem IR-Empfänger herstellen...
Da empfehle ich auch die schon genannte Version mit dem ESP8266 (Wemos D1 mini) und ESP-Now. Das sollte für deine Anwendung reichen. Der 1. (Server) gibt vor wann der 2. (Slave) was machen soll.
Bei ESP-Now braucht es keinen AP, sondern die beiden kommunizieren direkt miteinander.
#include <ESP8266WiFi.h> // for use with ESP32 use file "WiFi.h"
#include <espnow.h> // for use with ESP32 use file "esp_now.h" (underline in the middle)
// don't try to adapt this code to ESP32-modules
// ESP32-modules need another library with SUBSTANTIAL differencies
// go search for a demo-code that is written for ESP32
// if you want to receive ESP-NOW-messages reliably you have to strictly avoid
// the command delay(). Delay blocks the whole CPU and if a ESP-NOW-Message
// is send while the receivers CPU is blocked the receiving will fail
// so use a timing-function based on millis() like the one below instead.
boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - expireTime >= TimePeriod )
{
expireTime = currentMillis; // set new expireTime
return true; // more time than TimePeriod) has elapsed since last time if-condition was true
}
else return false; // not expired
}
unsigned long SendDataTimer;
//#############################################################################################
// list of MAC-Adresses of all receivers:
// important note: ESP-NOW sending is based on the RECEIVERS Mac-adress.
// this means for every ESP8266-modul that shall receive a ESP-NOW-Messages
// you have to execute register a peer in the Setup-function
// esp_now_add_peer(ESP_NOW_MAC_adr Of Recv, ESP_NOW_ROLE_COMBO, 1, NULL, 0);
// and you have to execute the command
// esp_now_send(ESP_NOW_MAC_adr Of Recv, (uint8_t *) &myESP_NOW_Data, sizeof(myESP_NOW_Data));
uint8_t ESP_NOW_MAC_adrOfRecv[] = { 0xF4, 0xCF, 0xA2, 0xD1, 0x3D, 0x28 }; // Board 0x06 sendet an Board 0x28
char MAC_adrOfRecv_as_AoC[18];
//##############################################################################################
// Structure example to send data. Must match the receiver structure
typedef struct MyESP_NOW_Data_type {
char MyESP_NOW_MsgStr[128];
int MyESP_NOW_Int;
} MyESP_NOW_Data_type;
// Create a "variable" called myESP_NOW_Data of variable-type MyESP_NOW_Data_type
MyESP_NOW_Data_type my_received_ESP_NOW_Data; //neu 2020.07.14-15:00
MyESP_NOW_Data_type my_READYtoSEND_ESP_NOW_Data; //neu 2020.07.14-15:00
void ESP_NOW_SendData()
{
// Set values to send
strcpy(my_READYtoSEND_ESP_NOW_Data.MyESP_NOW_MsgStr, "HI I'M SENDING EVERY TWO SECONDS COUNTiNG UP + 6");
my_READYtoSEND_ESP_NOW_Data.MyESP_NOW_Int = my_READYtoSEND_ESP_NOW_Data.MyESP_NOW_Int + 6;
// Send message via ESP-NOW
esp_now_send(ESP_NOW_MAC_adrOfRecv, (uint8_t *) &my_READYtoSEND_ESP_NOW_Data, sizeof(my_READYtoSEND_ESP_NOW_Data));
Serial.println("esp_now_send(ESP_NOW_MAC_adrOfRecv, (uint8_t *) &my_READYtoSEND_ESP_NOW_Data, sizeof(my_READYtoSEND_ESP_NOW_Data)); done");
Serial.print("I am the board with the MAC-Adress ");
Serial.println(WiFi.macAddress());
Serial.print("and I try to send my ESP-NOW-Data to the board with MAC-Adress ");
Serial.println(MAC_adrOfRecv_as_AoC);
// if sending has finished function OnDataSent is called
}
void ESP_Now_setup()
{
WiFi.mode(WIFI_STA);
Serial.println("WiFi.mode(WIFI_STA); done");
WiFi.disconnect(); // for strange reasons WiFi.disconnect() makes ESP-NOW work
Serial.println("WiFi.disconnect(); done");
// Init ESP-NOW
if (esp_now_init() != 0)
{
Serial.println("Error initializing ESP-NOW");
return;
}
Serial.println("esp_now_init() was successful");
esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
Serial.println("esp_now_set_self_role(ESP_NOW_ROLE_COMBO) done");
esp_now_register_recv_cb(OnDataRecv);
Serial.println("esp_now_register_recv_cb(OnDataRecv); done");
esp_now_register_send_cb(OnDataSent);
Serial.println("esp_now_register_send_cb(OnDataSent); done");
// each receiving unit must be registered. Register peer
esp_now_add_peer(ESP_NOW_MAC_adrOfRecv, ESP_NOW_ROLE_COMBO, 1, NULL, 0);
Serial.println("esp_now_add_peer(MAC_adressOfReceivingUnit, ESP_NOW_ROLE_COMBO, 1, NULL, 0) done");
for (int i=0;i<6;i++) {
strcat (MAC_adrOfRecv_as_AoC, hex02str(ESP_NOW_MAC_adrOfRecv[i]) );
if (i < 6) {
strcat (MAC_adrOfRecv_as_AoC, ":" );
}
}
MAC_adrOfRecv_as_AoC[17] = 0;
strupr(MAC_adrOfRecv_as_AoC); // make letters UPPERCASE
Serial.print("MAC-Adress of Receiver is ");
Serial.println(MAC_adrOfRecv_as_AoC);
}
void PrintFileNameDateTime()
{
Serial.print("Code running comes from file ");
Serial.println(__FILE__);
Serial.print("compiled ");
Serial.print(__DATE__);
Serial.println(__TIME__);
}
// print macadress of THIS device
// prepared for inserting code by copy & paste
// that will be flashed into receiving partner
void PrintWiFiMacAdress()
{
char MacAdr_AoC[18]; //suffix _AoC for easier remembering variable-type is ArrayOfChar
char HexByteDigits[3];
for (uint8_t i = 0; i < 18; i = i + 1)
{
MacAdr_AoC[i] = WiFi.macAddress()[i];
}
MacAdr_AoC[17] = 0; // zero to terminate the string
Serial.print("ESP Board Wifi.macAddress: ");
Serial.println(MacAdr_AoC);
Serial.println();
Serial.println("copy the line below and replace the codeline");
Serial.println("uint8_t ESP_NOW_MAC_adrOfRecv[] = { 0x60, 0x01, 0x94, 0x70, 0xAE, 0x7B };");
Serial.println("inside the code with the copied line from the serial monitor");
Serial.println();
Serial.print("uint8_t ESP_NOW_MAC_adrOfRecv[] = {");
for (uint8_t i = 0; i < 16; i = i + 3)
{
HexByteDigits[0] = MacAdr_AoC[i];
HexByteDigits[1] = MacAdr_AoC[i+1];
HexByteDigits[2] = 0; // zero for terminating the string
Serial.print("0x");
Serial.print(HexByteDigits);
if (i < 14) Serial.print(", ");
}
Serial.println(" };");
Serial.println();
}
char* hex02str(uint8_t b) {
static char str[]="FF"; // RAM für einen 2-Zeichen string reservieren.
snprintf(str,sizeof(str),"%02x",b);
return str;
}
// Callback when data is sent
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus)
{
Serial.print("Last Send Status: ");
if (sendStatus == 0)
{ Serial.println("Delivery Success"); }
else
{ Serial.println("Delivery failed"); }
}
// Callback function that will be executed when data is received
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t NoOfBytesRcv)
{
// copy data bytewise from variable incomingData to variable my_received_ESP_NOW_Data
memcpy(&my_received_ESP_NOW_Data, incomingData, sizeof(my_received_ESP_NOW_Data));
Serial.print("No of Bytes received: ");
Serial.println(NoOfBytesRcv);
//these lines must match the variables inside the ESP_NOW-data-structure
Serial.print("Array of Char: #");
Serial.print(my_received_ESP_NOW_Data.MyESP_NOW_MsgStr);
Serial.println("#");
Serial.print("Int: ");
Serial.println(my_received_ESP_NOW_Data.MyESP_NOW_Int);
Serial.println();
}
void setup()
{
// Init Serial Monitor
Serial.begin(115200);
Serial.println(); // a carriage return to make sure serial-output begins in colum 1 of a new line
PrintFileNameDateTime();
// Set device as a Wi-Fi Station
ESP_Now_setup();
PrintWiFiMacAdress();
}
void loop()
{
// check if timer-intervall is over
if (TimePeriodIsOver(SendDataTimer,2000) ) //neu 2020.07.14-15:00
{
Serial.println("SendData");
ESP_NOW_SendData();
Serial.println("SendData done");
}
}
Danke! Ich habe meine Problem soweit mit den beiden NodeMCU über ESP-Now lösen können. Was ich machen wollte funktioniert. Vielen Dank an alle die hier geholfen haben!
Mein Code für ESP-Now beruht im großen und ganzen auf dem Tutorial, was auch @Plumps gepostet hat (ESP8266).
Da dieses für meine Zwecke vollkommen ausreichend ist. Das Beispiel von @StefanL38 sieht auch sehr gut aus, aber da benötige ich mehr Zeit für die Einarbeit, die ich gerade für den Aufbau nicht habe, da dieser nächte Woche stehen muss.
Meine Lampensynchronisation beruht auf dieser Überlegung:
Der Sender läuft einfach seinen Rythmus durch und schaltet seine Lampe über einen Digitalausgang und gibt zusätzlich dem Empfänger zu bestimmten Zeiten das Signal um dessen Lampe auszuschalten. Da die Ausschaltzeit im Gegensatz zur Leuchtdauer immer gleich ist, ist die Lampe standartmäßig an beim Emfänger.