// ================================================ // commande de l'automotrice Egger-Bahn // version 5, adresse MAC d'origine, IP 70 // accélérations et ralentis progressifs, mode manoeuvre // ================================================ // https://www.tala-informatique.fr/wiki/index.php/Esp8266_udp_server // https://projetsdiy.fr/attribuer-ip-fixe-projet-arduino-esp32-esp8266-esp01/ #include #include #include // pour OTA // informations remontées au PC pour affichage #define sp Serial.print #define spl Serial.println const byte Moteur1 = 5; const byte Moteur2 = 4; const byte G0 = 16; const byte G1 = 2; // LED interne pour test const byte G2 = 0; const byte G3 = 13; const byte G4 = 14; const byte EEP = 12; const byte LED = 2; // LED interne char NbEssais = 10; // 10 essais à 500ms de connexion au réseau domestique bool EtatLed = false; unsigned long previousMillis = 0; const long interval = 200; const char Increment = 2, Decrement = 2; char sens, sensinst; int Vinst, Vobj, PWM; bool AccRal = false; // démarrage sans inertie // pour récupération des paquets UDP const uint16_t PORT = 21105; // Port d'écoute UDP Z21 const uint16_t BUFFER_SIZE = 512; // Taille du tampon de réception char buffer[BUFFER_SIZE]; // Tampon de réception uint16_t len = 0;// Taille du paquet reçu; // réponse quelconque (loco 3, checksum incluse) juste pour confirmer la liaison const char reponse[15] = {0x0F,0x00, 0x40,0x00, 0xEF,0x00, 0x03,0x00, 0x03, 0x00,0x00,0x00,0x00,0x00, 0xA0}; // instanciation du serveur UDP WiFiUDP udp; // ==================================================================================================== SETUP void setup() { char I; pinMode (Moteur1, OUTPUT); pinMode (Moteur2, OUTPUT); pinMode (G0, OUTPUT); pinMode (G1, OUTPUT); pinMode (G2, OUTPUT); pinMode (G3, OUTPUT); pinMode (G4, OUTPUT); pinMode (EEP, OUTPUT); digitalWrite(G0, HIGH); // Leds connectées au plus digitalWrite(G1, HIGH); // Leds connectées au plus digitalWrite(G2, HIGH); // Leds connectées au plus digitalWrite(G3, LOW); // sortie auxiliaire au moins digitalWrite(G4, HIGH); // Leds connectées au plus digitalWrite(EEP, LOW); // ENABLE digitalWrite (LED, HIGH); // Led interne connectée au plus Serial.begin(115200); // on démarre le port série delay(10); // On attend "un peu" que le buffer soit prêt // mode de fonctionnement: point d'accès ou station: setup_sta(); // essai en mode station sur réseau domestique if (NbEssais == 0) {setup_ap();} // sinon mode point d'accès // Démarrage de l'écoute udp.begin(PORT); sp("Démarrage de l'écoute sur le port "); spl(PORT); for (I=1; I<=3; I++){digitalWrite(LED,LOW); delay(200); digitalWrite(LED,HIGH); delay(200);} // clign } // ============================================================================================ fin de setup void setup_sta(){ // ============================================= SETUP EN MODE STATION (connexion à la box) const char sta_ssid[] = "SSID_box"; const char sta_password[] = "mot_de_passe"; //const char sta_address[12] = "192,168,1,70"; // adresse demandée const uint8_t mac[6] = {0x2C, 0x3A, 0xE8, 0x26, 0xA3, 0x54}; // "2c:3a:e8:26:a3:54" //WiFi.disconnect(true); // On efface la configuration précédente MAIS ÇA EMPÊCHE DE MODIFIER l'ADRESSE MAC // changement de l'adresse MAC cf: https://circuits4you.com/2017/12/31/how-to-change-esp8266-mac-address/ // pas de changement si on opère plusieurs engins spl(""); //sp("OLD ESP8266 MAC: "); //spl(WiFi.macAddress()); // This will read MAC Address of ESP //wifi_set_macaddr(0, const_cast(mac)); //changement MAC address pour Livebox sp("final ESP Board MAC Address: "); spl(WiFi.macAddress()); // demande d'une adresse IP précise WiFi.config({192,168,1,70},{192,168,1,1},{255,255,255,0},{192,168,1,1}); // IP, gateway, subnet, DNS // Initialisation de la connection WiFi WiFi.begin(sta_ssid, sta_password); spl("attente de la connexion"); // attente de connexion while (WiFi.status() != WL_CONNECTED && NbEssais >0 ){ delay(500); NbEssais--;} spl(NbEssais,DEC); // test if(WiFi.status()==WL_CONNECTED){ // pour OTA ArduinoOTA.setHostname("monEsp"); // on donne une petit nom a notre module ArduinoOTA.begin(); // initialisation de l'OTA // Affichage des informations sp("Connecté à "); sp(sta_ssid); // <<<<<<<<<< prendre la vraie valeur sp(" avec l'ip "); spl(WiFi.localIP()); } } void setup_ap(){ // ============================================================= SETUP EN MODE POINT D'ACCÈS //const char *ap_ssid = "JPM-8266"; //const char *ap_password = "12345678"; const char ap_ssid[] = "JPM-8266"; const char ap_password[] = "12345678"; spl(""); sp("Setting soft-AP configuration ... "); //spl(WiFi.softAPConfig(local_IP, gateway, subnet) ? "Ready" : "Failed!"); spl(WiFi.softAPConfig({192,168,1,70},{192,168,1,50},{255,255,255,0}) ? "Ready" : "Failed!"); sp("Starting soft-AP ... "); spl(WiFi.softAP(ap_ssid, ap_password) ? "Ready" : "Failed!"); sp("Soft-AP SSID = "); spl(ap_ssid); // <<<<<<<<<< prendre la vraie valeur sp("Soft-AP IP address = "); spl(WiFi.softAPIP()); } // ===================================================================================================== LOOP void loop() { unsigned long currentMillis = millis(); ArduinoOTA.handle(); // gestion OTA if (udp.parsePacket() > 0) { readPacket(); } // réception des paquets if (currentMillis - previousMillis >= interval) { // toutes les interval ms previousMillis = currentMillis; if (AccRal) { // gestion des changements de vitesse if (Vinst != Vobj) { // si vitesse de croisière, rien à faire if (Vobj > Vinst) { // accélérer Vinst = Vinst + Increment; if (Vinst > Vobj) { Vinst = Vobj;} } else { // ralentir Vinst = Vinst - Decrement; if (Vinst < Vobj) { Vinst = Vobj;} } ExecVitesse(); } } // end AccRal } // end if } // end loop // ==================================================================== récupération et affichage d'un paquet void readPacket() { // Mise en tampon du paquet len = udp.available(); udp.read(buffer, len); TraitementMessage(); // traitement du paquet } // ==================================================================================== envoi d'un paquet UDP void sendPacket(const char content[], IPAddress ip, uint16_t port) { udp.beginPacket(ip, port); udp.write(content); udp.endPacket(); } // =================================================================================== traitement des messages void TraitementMessage(){ // décodage des messages Z21 char GPIOx ; bool Commande ; // commande des fonctions // ---------------------------------------------- message F1 0A = get firmware version (initial) // send firmware version p.ex.: F3.0A.01.23.DB // ---------------------------------- message 0x00 = mode commande des locos, renvoyer loco info if(buffer[4]==0x00) { spl("passage en mode commande des locos, réponse: send loco info..."); sendPacket( reponse, udp.remoteIP(), udp.remotePort() ); } // ----------------------------------------------------- message 21 24 = get status (périodique) if (buffer[4]==0x21 && buffer[5]==0x24 ) { //spl(" get status (périodique)"); } // -------------------------------------------------- message E3 F0 = get loco info (périodique) if (buffer[4]==0xE3 && buffer[5]==0xF0 ) { // spl(" get loco info (périodique). Répondre..."); } // ------------------------------------------ message E4 13 = commande de vitesse 128 pas loco X if (buffer[4]==0xE4 && buffer[5]==0x13 ) { sp(" commande de vitesse 128 pas loco "); sp(buffer[7], DEC); Vobj = (buffer[8] & 127); sp(" Vobj: "); sp(Vobj); sens = (buffer[8] & 128); if (sensinst != sens) {Vinst = 0; Vobj = 0; ExecVitesse();} //arrêt if (sens==0) { spl(" sens 0"); } else { spl(" sens 1"); } sensinst = sens; analogWriteFreq(100); // PWM à 100Hz à 40000Hz if (!AccRal) { Vinst = Vobj; ExecVitesse();} } // -------------------------------------------------------- message 00 80 = set track power off if (buffer[3]==0x00 && buffer[4]==0x80 ) { sp(" set track power OFF"); Vinst = 0; Vobj = 0; ExecVitesse(); // arrêt instantané } // ---------------------------------------------------------- message 21 81 = set track power on if (buffer[4]==0x21 && buffer[5]==0x81 ) { Serial.println(" set track power ON"); // pas d'action } // --------------------------------------------- message E4 F8 = commande des fonctions loco X if (buffer[4]==0xE4 && buffer[5]==0xF8 ) { sp("loco "); sp(buffer[7], DEC); sp(" fonction "); sp(buffer[8] & 31); Commande = ((buffer[8] & 192)!=0); if(Commande) {spl(" ON");} else{spl(" OFF");} // commande des ports GPIO 14, 16, 13, 13, 2 par les fonctions 0,1,2,3,4 // filtrage des autres fonctions switch (buffer[8] & 31) { // fonction DCC case 0: { GPIOx = 14; // fanaux AV et AR if (Commande) { digitalWrite(GPIOx, LOW);} // connectés au plus else { digitalWrite(GPIOx, HIGH);} } break; case 1: { GPIOx = 16; // éclairage intérieur if (Commande) { digitalWrite(GPIOx, LOW);} // connecté au plus else { digitalWrite(GPIOx, HIGH);} } break; case 2: { GPIOx = 13; // klaxon 1 if (Commande) { digitalWrite(GPIOx, HIGH);} // le klaxon est connecté au moins else { digitalWrite(GPIOx, LOW);} } break; case 3: { GPIOx = 13; // klaxon 2 commandé en PWM pour essai if (Commande) { analogWrite(GPIOx, 80); } // le klaxon est connecté au moins else { digitalWrite(GPIOx, LOW);} } break; case 4: { GPIOx = 2; // LED du module pour tests if (Commande) { digitalWrite(GPIOx, LOW);} // connectée au plus else { digitalWrite(GPIOx, HIGH);} } break; case 6: { // mode avec/sans changement de vitesse progressif if (Commande) { AccRal = true;} else { AccRal = false; Vinst = Vobj; ExecVitesse();} } break; default: { // futures commandes de réglage sp("fonction "); sp(buffer[8] & 31); spl(" non traitée"); } break; } // end switch } // fin de traitement des fonctions } // fin de traitement des messages // ================================================================== commande effective de la vitesse void ExecVitesse() { // prise de la vitesse instantanée Vinst PWM = map(Vinst,0,127,0,1023); sp("Vobj: "); sp(Vobj,DEC); sp(" PWM: "); spl(PWM,DEC); // commande de la vitesse par enable (EEP) sur GPIO 12 if (sens==0) { digitalWrite(Moteur1, HIGH); digitalWrite(Moteur2, LOW); } else { digitalWrite(Moteur1, LOW); digitalWrite(Moteur2, HIGH); } analogWrite(EEP,PWM); } // ================================================================================== fin du programme