Anfängerfragen zu NodeMCU und programmierung mit der Arduino IDE

Begonnen von Ralf9, 23 April 2016, 18:30:55

Vorheriges Thema - Nächstes Thema

Ralf9

Hallo,

Ich habe seither nur mit dem Arduino gebastelt und programmiert,
nun möchte ich auch die NodeMCU verwenden.

Ich möchte die NodeMCU unter Linux (Opensuse 13.1) und der Arduino IDE 1.6.5 programmieren.
Ist es unter Linux egal ob die NodeMCU einen CP2102 oder CH340G verwendet?

Nach einigen Anleitungen, sollte die NodeMCU den ESP-12E haben.

Ich habe mal bei ebay geschaut.
Bei diesen beiden kann ich nicht erkennen ob ein ESP-12E verwendet wird.
NodeMcu Lua CH340G ESP8266 Wireless WIFI Internet Development Module DE TE390
NodeMCU Lua WIFI IOT Node EntwicklungsBoard ESP8266 micro USB 32bit Arduino

Edit:
Ich habe inzwischen einiges gelesen, demnach dürfte es egal sein welche NodeMCU ich nehme.


Wenn ich mit der Arduino IDE 1.6.5 die NodeMCU programmieren will, muß ich dies
http://arduino.esp8266.com/stable/package_esp8266com_index.json
unter Datei - Voreinstellungen eintragen.

Hier
http://arduino.esp8266.com/versions/1.6.5-947-g39819f0/doc/reference.html
steht, daß für den ESP8266 eine eigene EEPROM library verwendet wird.
Kann ich dann mit der Arduino IDE noch was für den Arduino unter Verwendung der EEPROM library, programmieren?

Gruß Ralf
FHEM auf Cubietruck mit Igor-Image, SSD und  hmland + HM-CFG-USB-2,  HMUARTLGW Lan,   HM-LC-Bl1PBU-FM, HM-CC-RT-DN, HM-SEC-SC-2, HM-MOD-Re-8, HM-MOD-Em-8
HM-Wired:  HMW_IO_12_FM, HMW_Sen_SC_12_DR, Selbstbau IO-Module HBW_IO_SW
Maple-SIGNALduino, WH3080,  Hideki, Id 7

Pf@nne

Klar,

der verwendete Core wird ja mit jedem Board "umgeschaltet".
Wenn ein du ESP - BOARD auswählst kompiliert Arduino mit dem passenden Core für die ESP-Architektur.

Das ist es ja, was Arduino ausmacht, für dich sehen die verwendeten Befehle immer gleich aus.
Arduino "übersetzt" diese dann für die entsprechende Architektur mittels der verwendeten Cors.

Damit sollte, zumindest theoretisch,  ein und der selbe Sketch auf einem Atmel wie auf einem ESP laufen.

Gruß
Pf@nne
FHEM auf: DS415+ (Master), Raspberry Pi 2

Ralf9

Zitat von: Pf@nne am 24 April 2016, 06:07:32
der verwendete Core wird ja mit jedem Board "umgeschaltet".
Wenn ein du ESP - BOARD auswählst kompiliert Arduino mit dem passenden Core für die ESP-Architektur.

Danke, damit ist es klar.

Ich werde diesen hier kaufen, der müsste passen:
http://www.ebay.de/itm/NodeMcu-Lua-CH340G-ESP8266-Wireless-WIFI-Internet-Development-Module-DE-TE390-/191816004111?hash=item2ca91ff20f:g:TqUAAOSw~OVW1B7g


Hier steht
http://arduino.esp8266.com/versions/1.6.5-947-g39819f0/doc/reference.html

The Program memory features work much the same way as on a regular Arduino; placing read only data and strings in read only memory
and freeing heap for your application. The important difference is that on the ESP8266 the literal strings are not pooled.
This means that the same literal string defined inside a F("") and/or PSTR("") will take up space for each instance in the code.
So you will need to manage the duplicate strings yourself.


Sehe ich das richtig, daß dies für mich nicht relevant ist, wenn ich nur F("") benutze.
Z.B. Serial.println(F("Unsupported command"));

Gruß Ralf
FHEM auf Cubietruck mit Igor-Image, SSD und  hmland + HM-CFG-USB-2,  HMUARTLGW Lan,   HM-LC-Bl1PBU-FM, HM-CC-RT-DN, HM-SEC-SC-2, HM-MOD-Re-8, HM-MOD-Em-8
HM-Wired:  HMW_IO_12_FM, HMW_Sen_SC_12_DR, Selbstbau IO-Module HBW_IO_SW
Maple-SIGNALduino, WH3080,  Hideki, Id 7

habeIchVergessen

#3
wenn ich mich recht erinnere (LaCrosseGateway), dann sind die NodeMCUs mit CH340G problematischer, als die mit CP2102.
ich verwende diesen.

PS: ich interessiere mich für signalduino auf esp8266-Basis.

Ralf9

Zitat von: habeIchVergessen am 24 April 2016, 11:54:41
PS: ich interessiere mich für signalduino auf esp8266-Basis.

Mit dem ESP-8266 als WiFi-Serial Bridge funktioniert es bereits:
http://www.hjgode.de/wp/2015/11/05/fhem-serielle-gerat-uber-wifi-anbinden/

Sidey hat vor zu testen ob der signalduino auch auf der NodeMCU läuft.
Die Wahrscheinlichkeit, daß es sauber funktioniert ist aber eher gering:
https://forum.fhem.de/index.php/topic,38831.msg438680.html#msg438680

Gruß Ralf
FHEM auf Cubietruck mit Igor-Image, SSD und  hmland + HM-CFG-USB-2,  HMUARTLGW Lan,   HM-LC-Bl1PBU-FM, HM-CC-RT-DN, HM-SEC-SC-2, HM-MOD-Re-8, HM-MOD-Em-8
HM-Wired:  HMW_IO_12_FM, HMW_Sen_SC_12_DR, Selbstbau IO-Module HBW_IO_SW
Maple-SIGNALduino, WH3080,  Hideki, Id 7

Ralf9

Zitat von: Ralf9 am 24 April 2016, 11:35:03
Ich werde diesen hier kaufen, der müsste passen:
http://www.ebay.de/itm/NodeMcu-Lua-CH340G-ESP8266-Wireless-WIFI-Internet-Development-Module-DE-TE390-/191816004111?hash=item2ca91ff20f:g:TqUAAOSw~OVW1B7g

Ich habe heute die nodemcu erhalten.

Das flashen mit der Arduino IDE 1.6.5 hat auf Anhieb problemlos funktioniert. Zu was wird die flashtaste benötigt?
Die Probleme mit der static IP konnte ich nicht nachvollziehen. Bei mir funktioniert es mit der static IP problemlos.

Ich habe mir zum Testen einen testsketch geschrieben.
Dabei ist mir aufgefallen, daß "server.println" nicht funktioniert. Mache ich da evtl was falsch?

#include <ESP8266WiFi.h>

const char* ssid = "***";
const char* pass = "***";

int var = 0;
int welcome = 0;

byte ip[] = { 192, 168, 0, x };
byte gateway[] = { 192, 168, 0, x };
byte subnet[] = { 255, 255, 255, 0 };

WiFiServer server(1000);
WiFiServer server1(23);   // für debug ausgabe
WiFiClient client;
WiFiClient client1;       // für debug ausgabe

void setup() {
  WiFi.begin(ssid, pass);
  WiFi.config(ip, gateway, subnet);
  uint8_t i = 0;
  while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500);
  if(i == 21){
    while(1) delay(500);
  }
  server.begin();
  server1.begin();
  server.setNoDelay(true);
  server1.setNoDelay(true);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop()
{
   //check if there are any new clients
   if (server.hasClient()){
     if (!client || !client.connected()) {
        if(client) {
           client.stop();
        }
        client = server.available();
        client.flush();
     }
   }
   if (server1.hasClient()){                  // debug client
     if (!client1 || !client1.connected()) {
        if(client1) {
           client1.stop();
        }
        client1 = server1.available();
        client1.flush();
     }
   }
   
   if (client && client.connected()){
      if(client.available()){
        if (welcome == 0) {
             client.println("welcome nodemcu");
             client1.println("welcome debug nodemcu");
             welcome = 1;
        }
        var = client.read();
        if (var == 97) {                            // a
           digitalWrite(LED_BUILTIN, HIGH);
           client.println("led aus");
           client1.println("LED aus");
        } else if (var == 98) {                     // b
           digitalWrite(LED_BUILTIN, LOW);
           client.println("led ein");
        } else if (var == 99) {                     // c
           client.print("Free Heap RAM: ");
           client.println(ESP.getFreeHeap());
        } else if (var == 100) {                    // d
           welcome = 0;
           client.println("welcome = 0");
        }
      }
   }
}


Gruß Ralf
FHEM auf Cubietruck mit Igor-Image, SSD und  hmland + HM-CFG-USB-2,  HMUARTLGW Lan,   HM-LC-Bl1PBU-FM, HM-CC-RT-DN, HM-SEC-SC-2, HM-MOD-Re-8, HM-MOD-Em-8
HM-Wired:  HMW_IO_12_FM, HMW_Sen_SC_12_DR, Selbstbau IO-Module HBW_IO_SW
Maple-SIGNALduino, WH3080,  Hideki, Id 7

Ralf9

Ich habe mir mit dieser Vorlage
https://github.com/kc-GitHub/HM485-Lib
ein HM-Wired Modul gebastelt, das direkt über Lan angebunden ist.
Nun bin ich gerade dabei, anpassungen für die NodeMCU vorzunehmen. Einiges funktioniert schon.

Siehe Anlage:
Der HBW_IO_SW_HBW8555631 ist ein Arduino Mega 2560 mit ethernet shield.
Der HBW_IO_SW_ESP8266000 ist eine NodeMCU.

Ich habe noch ein paar Fragen/Probleme:

Da die NodeMCU nur sehr wenig GPIOs hat, möchte ich für die "keys" den MCP23017 mit der "Adafruit_MCP23017_Arduino_Library" verwenden.
Ich möchte dann die handleKeys Routine nur noch alle 50ms aufrufen. Hat dies irgendwelche Nachteile?
Momentan wird sie noch bei jedem loop durchlauf aufgerufen.

// Tastenkey,  es sind 12 Tasten definiert
void handleKeys() {
  // millis() zum Zeitpunkt eines Tastendrucks
  // verwendet zum Entprellen, lange Tastendruecke und wiederholtes Senden langer Tastendruecke
  static unsigned long keyPressedMillis[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
  static byte keyPressNum[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
  static unsigned long lastSentLong[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
  boolean portStat;
 
  unsigned long now = millis();

  for(byte i = 0; i < NUM_KEYS; i++) {
// INPUT_LOCKED?
if(!config.keys[i].input_locked) continue;   // inverted logic, locked = 0
portStat = bitRead(keyPortStatus[i/8],i%8);
if (!config.keys[i].input_inverted) {       // inverted
portStat = !portStat; 
}
if (portStat) {      //  1 = Taste nicht gedrueckt
// Taste war auch vorher nicht gedrueckt kann ignoriert werden
// Taste war vorher gedrueckt?
if(keyPressedMillis[i]) {
// entprellen, nur senden, wenn laenger als 50ms gedrueckt
// aber noch kein "long" gesendet
if(now - keyPressedMillis[i] >= 50 && !lastSentLong[i]) {
keyPressNum[i]++;
hmwmodule->broadcastKeyEvent(i + CHANNEL_START_KEYS, keyPressNum[i]);
triggerPeeringTime(i, 255, 0); // 0 = short
}
keyPressedMillis[i] = 0;
}
}
else { // Taste gedrueckt
if(keyPressedMillis[i]) { // Taste war vorher schon gedrueckt
// muessen wir ein "long" senden?
if(lastSentLong[i]) {   // schon ein LONG gesendet
if(now - lastSentLong[i] >= 300) {    // alle 300ms wiederholen
// keyPressNum nicht erhoehen
lastSentLong[i] = now ? now : 1; // der Teufel ist ein Eichhoernchen
hmwmodule->broadcastKeyEvent(i + CHANNEL_START_KEYS, keyPressNum[i], true);
}
}
else if (millis() - keyPressedMillis[i] >= long(config.keys[i].long_press_time * 100)) {
// erstes LONG
keyPressNum[i]++;
lastSentLong[i] = millis();
hmwmodule->broadcastKeyEvent(i + CHANNEL_START_KEYS,keyPressNum[i], true);
triggerPeeringTime(i, 255, 1);  // 1 = long
}
}
else {
// Taste war vorher nicht gedrueckt
keyPressedMillis[i] = now ? now : 1; // der Teufel ist ein Eichhoernchen
lastSentLong[i] = 0;
}
}
  } // for
}




Sehe ich das richtig, daß ich für das EEPROM.read das
EEPROM.begin(1024);
nur einmal im setup() aufrufen muß?


Mit der folgenden readConfig Routine wird die "struct hmw_config" eingelesen.
Bei der NodeMCU musste ich den ptr korrigieren (ptr += 3;). Beim Arduino ist dies nicht notwendig.
Hat dafür jemand eine Erklärung?

hmw_config config;

   void readConfig(){
      byte* ptr;
      printConfigFlag = true;
      // EEPROM lesen
      ptr = (byte*)(&config);
      ptr += 3;
      for(int address = 0; address < (sizeof(config)-3); address++){
         *ptr = EEPROM.read(address + 0x01);
         ptr++;
      }
     ..
   }


Hier ist ein Auszug aus der HMWRegister.h

// Sensor
struct hmw_config_sensor {
byte input_locked          :1;   //     0=LOCKED, 1=UNLOCKED
        byte input_inverted        :1;   //     0=inverted 1=normal
        byte input_pullup          :1;   //                1=PULLUP
        byte                       :5;   //
};

// Taster
struct hmw_config_key {
byte input_type            :1;   //     0=SWITCH,  1=PUSHBUTTON
byte input_locked          :1;   //     0=LOCKED,  1=UNLOCKED
byte input_inverted        :1;   //     0=inverted 1=normal
        byte input_pullup          :1;   //                1=PULLUP
        byte                       :4;
byte long_press_time;            //     in sec/10
};


struct hmw_config {
byte logging_time;             // 0x01
long central_address;          // 0x02 - 0x05
byte direct_link_deactivate:1; // 0x06 
byte                       :7; 
     hmw_config_sensor sensors[16];    // 0x07 - 0x16
     hmw_config_key keys[16];          // 0x17 - 0x36
}
FHEM auf Cubietruck mit Igor-Image, SSD und  hmland + HM-CFG-USB-2,  HMUARTLGW Lan,   HM-LC-Bl1PBU-FM, HM-CC-RT-DN, HM-SEC-SC-2, HM-MOD-Re-8, HM-MOD-Em-8
HM-Wired:  HMW_IO_12_FM, HMW_Sen_SC_12_DR, Selbstbau IO-Module HBW_IO_SW
Maple-SIGNALduino, WH3080,  Hideki, Id 7

Ralf9

Zitat von: Ralf9 am 26 Mai 2016, 22:53:28
Da die NodeMCU nur sehr wenig GPIOs hat, möchte ich für die "keys" den MCP23017 mit der "Adafruit_MCP23017_Arduino_Library" verwenden.
Ich möchte dann die handleKeys Routine nur noch alle 50ms aufrufen. Hat dies irgendwelche Nachteile?
Momentan wird sie noch bei jedem loop durchlauf aufgerufen.

Da dies anscheinend keine Nachteile hat, habe ich es nun umgestellt, daß die handleKeys Routine nur noch alle 50ms aufrufen und der MCP23017 verwendet wird.
Das müsste so jetzt passen:
// Tastenkey,  es sind max 12 Tasten definiert
void handleKeys() {
  static byte keyPressed50ms[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
  static byte keyPressNum[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
  static byte lastSentLong[2] = {0,0};    // wurde bereits long gesendet?
  static byte flag[2] = {0,0};
  boolean portStat;
  byte i;

//  KEY_CHANNEL_PORTS
//  for(i = 0; i < NUM_KEYS; i++){
//    // Pin lesen und Bit in portStatus setzen
//    bitWrite(keyPortStatus[i/8],i%8,digitalRead(keyChannelPorts[i]));
//  }

  keyPortStatus[0] = mcp.readGPIO(0);
  if (NUM_KEYS > 8) {
     keyPortStatus[1] = mcp.readGPIO(1);
  }

//for(i = 0; i < NUM_KEYS; i++) {
//  bitWrite(keyPortStatus[i/8],i%8, bitRead(a,i);
//}

  for(i = 0; i < NUM_KEYS; i++) {
     // INPUT_LOCKED?
    if(!config.keys[i].input_locked) continue;   // inverted logic, locked = 0
    portStat = bitRead(keyPortStatus[i/8],i%8);
    if (!config.keys[i].input_inverted) {       // inverted
       portStat = !portStat; 
    }
    if (portStat) {      //  1 = Taste nicht gedrueckt (negative Logik wegen INPUT_PULLUP)
      // Taste war auch vorher nicht gedrueckt kann ignoriert werden
      // Taste war vorher gedrueckt?
      if(keyPressed50ms[i]) {
        // entprellen, nur senden, wenn laenger als 50ms gedrueckt, aber noch kein "long" gesendet
        if (!bitRead(lastSentLong[i/8], i%8)) {    // war kein long
          if(keyPressed50ms[i] >= 2) {
            keyPressNum[i]++;
            keyPressed50ms[i] = 0;
            hmwmodule->broadcastKeyEvent(i + CHANNEL_START_KEYS, keyPressNum[i]);
            triggerPeeringTime(i, 255, 0);  // 0 = short
          } else {
            keyPressed50ms[i] = 2;
          }
        } else {  // war long
          keyPressed50ms[i] = 0;
          bitClear(lastSentLong[i/8], i%8);
        }
      } else {
        bitClear(flag[i/8], i%8);   // Flag = 0
      }
    }       // Taste gedrueckt
    else {
      if(config.keys[i].input_type) {        // pushbutton
        // Taste war vorher schon gedrueckt
        if(keyPressed50ms[i]) {
          // muessen wir ein "long" senden?
          if(bitRead(lastSentLong[i/8], i%8)) {   // schon ein LONG gesendet
             if(keyPressed50ms[i] >= 6) {         // alle 300ms wiederholen
               // keyPressNum nicht erhoehen
               keyPressed50ms[i] = 0;
               hmwmodule->broadcastKeyEvent(i + CHANNEL_START_KEYS, keyPressNum[i], true);  // true = long
            }
          } else if (keyPressed50ms[i] >= (config.keys[i].long_press_time * 2)) {
            // erstes LONG
            keyPressNum[i]++;
            keyPressed50ms[i] = 0;
            bitSet(lastSentLong[i/8], i%8);
            hmwmodule->broadcastKeyEvent(i + CHANNEL_START_KEYS, keyPressNum[i], true);  // true = long
            triggerPeeringTime(i, 255, 1); // 1 = long
          }
          keyPressed50ms[i]++;
        } else {
          // Taste war vorher nicht gedrueckt
          keyPressed50ms[i] = 1;
          bitClear(lastSentLong[i/8], i%8);
        }
      } else {           // type = switch
        if(!keyPressed50ms[i]) {
          if (bitRead(flag[i/8], i%8) == 1) {        // flag
            bitClear(flag[i/8], i%8);   // flag = 0
            keyPressNum[i]++;
            keyPressed50ms[i] = 1;
            hmwmodule->broadcastKeyEvent(i + CHANNEL_START_KEYS, keyPressNum[i]);
            triggerPeeringTime(i, 255, 0);  // 0 = short
          } else {
            bitSet(flag[i/8], i%8);   // flag = 1
          }
        }
      } // type
    }
  } // for
}



Nun habe ich alles was ich wollte hinbekommen.
Die nodemcu ist über wlan mit dem HM-wired Protokoll angebunden.
Es sind max 16 Sensoren für Kontakte und max 16 Tastereingänge (short/long) möglich.
Es sind auch bis zu 8 Ausgänge möglich. Ich habe auch ein vereinfachtes internes peering eingebaut.
Bei Bedarf sind auch bis zu 4 Rollos möglich. 

Gruß Ralf
FHEM auf Cubietruck mit Igor-Image, SSD und  hmland + HM-CFG-USB-2,  HMUARTLGW Lan,   HM-LC-Bl1PBU-FM, HM-CC-RT-DN, HM-SEC-SC-2, HM-MOD-Re-8, HM-MOD-Em-8
HM-Wired:  HMW_IO_12_FM, HMW_Sen_SC_12_DR, Selbstbau IO-Module HBW_IO_SW
Maple-SIGNALduino, WH3080,  Hideki, Id 7