Site icon Renzo Mischianti

MKS WIFI for Makerbase Robin: firmware upgrade and new Web Socket features – 4

Spread the love

I bought a FlyingBear Ghost 5 with an integrated WiFi module, but I discovered no web interface. I don’t know why they can’t add a basic user interface. Then I went to see the web interface of the high-end Makerbase cards and realized that it was better they didn’t develop it.

My solution was to modify the firmware to support the Web Socket and develop the Web interface. This feature is compatible with all Makerbase cards with an MKS WiFi module.

Makerbase MKS wifi firmware upgrade mischianti

The result of the BeePrint Web interface is in this screenshot.

MKS WiFi BeePrint interface of my FlyingBear Ghost 5

I also decided to explain all the development phases of the project. In this article, I would like to expose the hardware infrastructure of the MKS WiFi card that interfaces with the Makerbase Robin Nano.

Now we will analyze the changes I made to the original MKS WiFi module, with the introduction of Web Socket and some minor features to develop Web interface and debug.

MKS WiFi upgrades

I made some changes to the original code, the old functions remain the same, but I must add a WebSocket server service and some endpoint for additional features.

But these changes use a bit of additional memory, so we lost the OTA update for Filesystem. When we need to upload the Filesystem again, we must downgrade the firmware, upload the Filesystem and upload the firmware again.

WebSocket code

The section that manages the message is this.

bool manageMessage(char* readStr, int readSize){
  //transfer file
  #if 0
  if(strstr((const char *)readStr, "M29") != 0)
  {
    if(!verification_flag)
    {
      break;
    }
    if(transfer_state != TRANSFER_IDLE)
    {
      rcv_end_flag = true;
      net_print((const uint8_t *) "ok\n", strlen((const char *)"ok\n"));
      break;
    }
  }
  #endif

  DEBUG_PRINT(F("transfer_file_flag "));
  DEBUG_PRINTLN(transfer_file_flag);

  DEBUG_PRINT(F("verification_flag "));
  DEBUG_PRINTLN(verification_flag);

  DEBUG_PRINT(F("readStr "));
  DEBUG_PRINTLN(readStr);

  DEBUG_PRINT(F("readSize "));
  DEBUG_PRINTLN(readSize);


  if(transfer_file_flag)
  {

    if(!verification_flag)
    {
      return false;
    }
    if(gFileFifo.left() >= readSize)
    {

      gFileFifo.push((char *)readStr, readSize);
      transfer_frags += readSize;


    }

  }
  else
  {


    if(verification_flag)
    {
      int j = 0;
      char cmd_line[100] = {0};
      String gcodeM3 = "";

    #if 0
      if(transfer_state == TRANSFER_BEGIN)
      {
        if(strstr((const char *)readStr, "M110") != 0)
        {

          file_fragment = 0;
          rcv_end_flag = false;
          transfer_file_flag = true;

          if(package_file_first(filePath) == 0)
          {
            /*transfer_state = TRANSFER_READY;
            digitalWrite(EspReqTransferPin, LOW);*/
          }
          else
          {
            transfer_file_flag = false;
            transfer_state = TRANSFER_IDLE;
          }
          net_print((const uint8_t *) "ok\n", strlen((const char *)"ok\n"));
          break;
        }
      }

    #endif

      init_queue(&cmd_queue);

      cmd_index = 0;
      memset(cmd_fifo, 0, sizeof(cmd_fifo));
      while(j < readSize)
      {
        if((readStr[j] == '\r') || (readStr[j] == '\n'))
        {
          if((cmd_index) > 1)
          {
            cmd_fifo[cmd_index] = '\n';
            cmd_index++;


            push_queue(&cmd_queue, cmd_fifo, cmd_index);
          }
          memset(cmd_fifo, 0, sizeof(cmd_fifo));
          cmd_index = 0;
        }
        else if(readStr[j] == '\0')
          break;
        else
        {
          if(cmd_index >= sizeof(cmd_fifo))
          {
            memset(cmd_fifo, 0, sizeof(cmd_fifo));
            cmd_index = 0;
          }
          cmd_fifo[cmd_index] = readStr[j];
          cmd_index++;
        }

        j++;

        do_transfer();
        yield();

      }
      while(pop_queue(&cmd_queue, cmd_line, sizeof(cmd_line)) >= 0)
      {
      #if 0
        point = strstr((const char *)cmd_line, "M28 ");
        if(point != 0)
        {
          if((strstr((const char *)cmd_line, ".g") || strstr((const char *)cmd_line, ".G")))
          {
            int index = 0;
            char *fileName;

            point += 3;
            while(*(point + index) == ' ')
              index++;

            memcpy((char *)filePath, (const char *)(point + index), readSize - (int)(point + index - (int)(&cmd_line[0])));

            gFileFifo.reset();

            transfer_frags = 0;


            transfer_state = TRANSFER_BEGIN;

            sprintf((char *)dbgStr, "Writing to file:%s\n", (char *)filePath);

            net_print((const uint8_t *)dbgStr, strlen((const char *)dbgStr));
          }

        }
        else
      #endif
        {
          /*transfer gcode*/
          //Serial.write(cmd_line, readNum);
          if((strchr((const char *)cmd_line, 'G') != 0)
            || (strchr((const char *)cmd_line, 'M') != 0)
            || (strchr((const char *)cmd_line, 'T') != 0))
          {
            if(strchr((const char *)cmd_line, '\n') != 0 )
            {
              String gcode((const char *)cmd_line);

            //  sprintf((char *)dbgStr, "read %d: %s\n", readNum, cmd_line);

          //    net_print((const uint8_t *)dbgStr, strlen((char *)dbgStr));

              if(gcode.startsWith("M998") && (M3_TYPE == ROBIN))
              {
                net_print((const uint8_t *) "ok\r\n", strlen((const char *)"ok\r\n"));
              }
              else if(gcode.startsWith("M997"))
              {
                if(gPrinterInf.print_state == PRINTER_IDLE)
                //  net_print((const uint8_t *) "M997 IDLE\r\n", strlen((const char *)"M997 IDLE\r\n"));
                  strcpy((char *)dbgStr, "M997 IDLE\r\n");
                else if(gPrinterInf.print_state == PRINTER_PRINTING)
                //  net_print((const uint8_t *) "M997 PRINTING\r\n", strlen((const char *)"M997 PRINTING\r\n"));
                  strcpy((char *)dbgStr, "M997 PRINTING\r\n");
                else if(gPrinterInf.print_state == PRINTER_PAUSE)
                  //net_print((const uint8_t *) "M997 PAUSE\r\n", strlen((const char *)"M997 PAUSE\r\n"));
                  strcpy((char *)dbgStr, "M997 PAUSE\r\n");
                else
                  strcpy((char *)dbgStr, "M997 NOT CONNECTED\r\n");
              //  net_print((const uint8_t *) "ok\r\n", strlen((const char *)"ok\r\n"));
              }
              else if(gcode.startsWith("M27"))
              {
                memset(dbgStr, 0, sizeof(dbgStr));
                sprintf((char *)dbgStr, "M27 %d\r\n", gPrinterInf.print_file_inf.print_rate);
              //  net_print((const uint8_t *) dbgStr, strlen((const char *)dbgStr));
              //  net_print((const uint8_t *) "ok\r\n", strlen((const char *)"ok\r\n"));
              }
              else if(gcode.startsWith("M992"))
              {
                memset(dbgStr, 0, sizeof(dbgStr));
                sprintf((char *)dbgStr, "M992 %02d:%02d:%02d\r\n",
                  gPrinterInf.print_file_inf.print_hours, gPrinterInf.print_file_inf.print_mins, gPrinterInf.print_file_inf.print_seconds);
              //  net_print((const uint8_t *) dbgStr, strlen((const char *)dbgStr));
              //  net_print((const uint8_t *) "ok\r\n", strlen((const char *)"ok\r\n"));
              }
              else if(gcode.startsWith("M994"))
              {
                memset(dbgStr, 0, sizeof(dbgStr));
                sprintf((char *)dbgStr, "M994 %s;%d\r\n",
                  gPrinterInf.print_file_inf.file_name.c_str(), gPrinterInf.print_file_inf.file_size);
              //  net_print((const uint8_t *) dbgStr, strlen((const char *)dbgStr));
              //  net_print((const uint8_t *) "ok\r\n", strlen((const char *)"ok\r\n"));
              }
              else  if(gcode.startsWith("M115"))
              {
                memset(dbgStr, 0, sizeof(dbgStr));
                if(M3_TYPE == ROBIN)
                  strcpy((char *)dbgStr, "FIRMWARE_NAME:Robin\r\n");
                else if(M3_TYPE == TFT28)
                  strcpy((char *)dbgStr, "FIRMWARE_NAME:TFT28/32\r\n");
                else if(M3_TYPE == TFT24)
                  strcpy((char *)dbgStr, "FIRMWARE_NAME:TFT24\r\n");


              //  net_print((const uint8_t *) dbgStr, strlen((const char *)dbgStr));
              //  net_print((const uint8_t *) "ok\r\n", strlen((const char *)"ok\r\n"));
              }
              /*else if(gcode.startsWith("M105"))
              {
                memset(dbgStr, 0, sizeof(dbgStr));
                sprintf((char *)dbgStr, "T:%d /%d B:%d /%d T0:%d /%d T1:%d /%d @:0 B@:0\r\n",
                  (int)gPrinterInf.curSprayerTemp[0], (int)gPrinterInf.desireSprayerTemp[0], (int)gPrinterInf.curBedTemp, (int)gPrinterInf.desireBedTemp,
                  (int)gPrinterInf.curSprayerTemp[0], (int)gPrinterInf.desireSprayerTemp[0], (int)gPrinterInf.curSprayerTemp[1], (int)gPrinterInf.desireSprayerTemp[1]);

              //  net_print((const uint8_t *) dbgStr, strlen((const char *)dbgStr));
              //  net_print((const uint8_t *) "ok\r\n", strlen((const char *)"ok\r\n"));
              }*/
              else
              {
                DEBUG_PRINT(F("GCODE COMMANDS "));
                DEBUG_PRINTLN(gcode);

                if(gPrinterInf.print_state == PRINTER_IDLE)
                {
                  if(gcode.startsWith("M23") || gcode.startsWith("M24"))
                   {
                    gPrinterInf.print_state = PRINTER_PRINTING;
                    gPrinterInf.print_file_inf.file_name = "";
                    gPrinterInf.print_file_inf.file_size = 0;
                    gPrinterInf.print_file_inf.print_rate = 0;
                    gPrinterInf.print_file_inf.print_hours = 0;
                    gPrinterInf.print_file_inf.print_mins = 0;
                    gPrinterInf.print_file_inf.print_seconds = 0;

                    printFinishFlag = false;
                   }
                }
                gcodeM3.concat(gcode);

              }

            }
          }
        }
        if(strlen((const char *)dbgStr) > 0)
        {
          net_print((const uint8_t *) "ok\r\n", strlen((const char *)"ok\r\n"));

          net_print((const uint8_t *) dbgStr, strlen((const char *)dbgStr));
          memset(dbgStr, 0, sizeof(dbgStr));

        }



        do_transfer();
        yield();



      }

      if(gcodeM3.length() > 2)
      {
        package_gcode(gcodeM3, true);
        //Serial.write(uart_send_package, sizeof(uart_send_package));
        /*transfer_state = TRANSFER_READY;
        digitalWrite(EspReqTransferPin, LOW);*/
        do_transfer();

        socket_busy_stamp = millis();
      }


    }
  }
  return true;

}

I wrote a function that isolated the code to call this function in the previous management zone and the new management of TCP messages.

    {
      if (tcp.hasClient()){
        for(i = 0; i < MAX_SRV_CLIENTS; i++){
          //find free/disconnected spot
        #if 0
          if (!serverClients[i] || !serverClients[i].connected()){
          if(serverClients[i]) serverClients[i].stop();
          serverClients[i] = tcp.available();
          continue;
          }
          #else
          if(serverClients[i].connected())
          {
          serverClients[i].stop();
          }
          #endif
          serverClients[i] = tcp.available();
        }
        if (tcp.hasClient())
        {
          //no free/disconnected spot so reject
          WiFiClient serverClient = tcp.available();
          serverClient.stop();

        }
      }
      memset(dbgStr, 0, sizeof(dbgStr));
      for(i = 0; i < MAX_SRV_CLIENTS; i++)
      {
        if (serverClients[i] && serverClients[i].connected())
        {
          uint32_t readNum = serverClients[i].available();

          if(readNum > FILE_FIFO_SIZE)
          {
          //  net_print((const uint8_t *) "readNum > FILE_FIFO_SIZE\n");
            serverClients[i].flush();
          //  Serial.println("flush");
            continue;
          }


          if(readNum > 0)
          {
            char * point;

              uint8_t readStr[readNum + 1] ;

            uint32_t readSize;

            readSize = serverClients[i].read(readStr, readNum);

            readStr[readSize] = 0;

            if (!manageMessage((char*)readStr, readSize)) break;
          }
        }
      }

and here is the management in the WS listener.

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
  DynamicJsonDocument docwsT(512);
  DeserializationError error;

    switch(type) {
        case WStype_DISCONNECTED:
      webSocket.sendTXT(num, "{\"connection\": false}");

            DEBUG_PRINT(F(" Disconnected "));
            DEBUG_PRINTLN(num, DEC);

            isConnectedWebSocket = false;
//            isConnectedWebSocketAck = false;
//            DEBUG_PRINTF_AI(F("[%u] Disconnected!\n"), num);
            break;
        case WStype_CONNECTED:
            {
                IPAddress ip = webSocket.remoteIP(num);
//                DEBUG_PRINTF_AI(F("[%u] Connected from %d.%d.%d.%d url: %s\n"), num, ip[0], ip[1], ip[2], ip[3], payload);

                DEBUG_PRINT(num);
                DEBUG_PRINT(F("Connected from: "));
                DEBUG_PRINT(ip.toString());
                DEBUG_PRINT(F(" "));
                DEBUG_PRINTLN((char*)payload);

        // send message to client
//        webSocket.sendTXT(num, "{\"type\":\"connection\", \"connection\": true, \"simpleMessage\": "+String(readSingleMessage?"true":"false")+"}");

        isConnectedWebSocket = true;

        memset(dbgStr, 0, sizeof(dbgStr));
        sprintf((char *)dbgStr, "FWV:%s\r\n", firmwareVersion);
        net_print((const uint8_t*)dbgStr, strlen((const char *)dbgStr));

            }
            break;
        case WStype_TEXT:
          DEBUG_PRINT("NUM -> ");DEBUG_PRINT(num);
          DEBUG_PRINT("payload -> ");DEBUG_PRINTLN((char*)payload);

          manageMessage((char*)payload, length);
//          manageMessage(String((char*)payload));
//          error = deserializeJson(docwsT, (char*)payload);
//
//          if (error) {
//            // if the file didn't open, print an error:
//            DEBUG_PRINT(F("Error parsing JSON "));
//            webSocket.broadcastTXT("Error on WS");
//          }else{
//            JsonObject postObjws = docwsT.as<JsonObject>();
//
//            bool startReceiveDevMsg = postObjws[F("startReceiveDevMsg")];
//            if (startReceiveDevMsg==true){
////          readSingleMessage = postObjws[F("singleMessage")];
//          isConnectedWebSocketAck  = true;
//          DEBUG_PRINT(F("Start listening messages SM -> "));
//          DEBUG_PRINTLN(isConnectedWebSocketAck);
//
//              webSocket.broadcastTXT("{\"type\": \"device_msg\", \"receiving\": true}");
//            }else if (startReceiveDevMsg==false){
//          isConnectedWebSocketAck  = false;
//          DEBUG_PRINT(F("Start listening messages SM -> "));
//          DEBUG_PRINTLN(isConnectedWebSocketAck);
//
//          webSocket.broadcastTXT("{\"type\": \"device_msg\", \"receiving\": false}");
//            }
//
//        bool singleMessage = postObjws[F("singleMessage")];
//        DEBUG_PRINT(F("Single message -> "));
//        DEBUG_PRINTLN(singleMessage);
//            if (singleMessage){
//          readSingleMessage = singleMessage;
//            }
//          }

//          DEBUG_PRINTF_AI(F("[%u] get Text: %s\n"), num, payload);

            // send message to client
            // webSocket.sendTXT(num, "message here");

            // send data to all connected clients
            // webSocket.broadcastTXT("message here");
            break;
        case WStype_BIN:
////          DEBUG_PRINTF_AI(F("[%u] get binary length: %u\n"), num, length);
//            hexdump(payload, length);
//
//            // send message to client
//            // webSocket.sendBIN(num, payload, length);
//            break;
        case WStype_ERROR:
        case WStype_FRAGMENT_TEXT_START:
        case WStype_FRAGMENT_BIN_START:
        case WStype_FRAGMENT:
        case WStype_FRAGMENT_FIN:
        case WStype_PING:
        case WStype_PONG:

//          DEBUG_PRINTF_AI(F("[%u] get binary length: %u\n"), num, length);
          DEBUG_PRINT(F("WS : "))
          DEBUG_PRINT(type)
          DEBUG_PRINT(F(" - "))
      DEBUG_PRINTLN((char*)payload);

            // send message to client
            // webSocket.sendBIN(num, payload, length);
            break;
    }

}

Test WebSocket

You can connect with the simple WebSocket client that you can find in this article.

WebSocket client connected to MKS WiFi

When the connection starts, you receive the temperature and WiFi information. You can try to add a command like M20 1:, pay attention to the return at the end (use shift + enter), and you receive a set of messages like

REST end points

By default, only one endpoint is exposed, the file upload.

To develop a Web Interface first, I will enable CORS requests. Refer to this tutorial “How to create a REST server on esp8266 or esp32: CORS request, OPTION, and POST“.

Where sendCrossOriginHeader is managed by ENABLE_CORS define.

void setCrossOrigin(){
#ifdef ENABLE_CORS
    server.sendHeader(F("Access-Control-Allow-Origin"), F("*"));
    server.sendHeader(F("Access-Control-Max-Age"), F("600"));
    server.sendHeader(F("Access-Control-Allow-Methods"), F("PUT,POST,GET,OPTIONS"));
    server.sendHeader(F("Access-Control-Allow-Headers"), F("*"));
#endif
};

void sendCrossOriginHeader(){
    DEBUG_PRINTLN(F("sendCORSHeader"));
    server.sendHeader(F("access-control-allow-credentials"), F("false"));
    setCrossOrigin();
    server.send(204);
}

As you can see, It isn’t a multipart form data, but It wants a stream of the file in raw format.

void handleUpload()
{
  DEBUG_PRINTLN(F("Upload request!"));

  setCrossOrigin();

  uint32_t now;
  uint8_t readBuf[1024];

  uint32_t postLength = server.getPostLength();
  String uri = server.uri();


  if(uri != NULL)
  {
    if((transfer_file_flag) || (transfer_state != TRANSFER_IDLE) || (gPrinterInf.print_state != PRINTER_IDLE))
  {
    server.send(409, FPSTR(STR_MIME_TEXT_PLAIN), FPSTR("409 Conflict"));
    return;
  }

    if(server.hasArg((const char *) "X-Filename"))
    {
      if((transfer_file_flag) || (transfer_state != TRANSFER_IDLE))
      {
        server.send(500, FPSTR(STR_MIME_APPLICATION_JSON), FPSTR(STR_JSON_ERR_500_IS_BUSY));
      return;
      }

    file_fragment = 0;
    rcv_end_flag = false;
    transfer_file_flag = true;
    gFileFifo.reset();
    upload_error = false;
    upload_success = false;

    String FileName = server.arg((const char *) "X-Filename");
    //package_gcode(FileName, true);
    //transfer_state = TRANSFER_READY;
    //digitalWrite(EspReqTransferPin, LOW);
    //String fileNameAfterDecode = urlDecode(FileName);
    //package_gcode(fileNameAfterDecode, true);
    //transfer_state = TRANSFER_READY;
    //digitalWrite(EspReqTransferPin, LOW);
    if(package_file_first((char *)FileName.c_str(), (int)postLength) == 0)
    {
      /*transfer_state = TRANSFER_READY;
      digitalWrite(EspReqTransferPin, LOW);*/
    }
    else
    {
      transfer_file_flag = false;
    }
    /*wait m3 reply for first frame*/
    int wait_tick = 0;
    while(1)
    {
      do_transfer();

      delay(100);

      wait_tick++;

      if(wait_tick > 20) // 2s
      {
        if(digitalRead(McuTfrReadyPin) == HIGH) // STM32 READY SIGNAL
        {
          upload_error = true;
        //  Serial.println("upload_error");
        }
        else
        {
      //    Serial.println("upload_sucess");
        }
        break;
      }

      int len_get = get_printer_reply();
      if(len_get > 0)
      {
        esp_data_parser((char *)uart_rcv_package, len_get);

        uart_rcv_index = 0;
      }

      if(upload_error)
      {
        break;
      }
    }

    if(!upload_error)
    {

       now = millis();
      do
      {
        do_transfer();

        int len = get_printer_reply();

        if(len > 0)
        {
        //  Serial.println("rcv");
          esp_data_parser((char *)uart_rcv_package, len);

          uart_rcv_index = 0;
        }

        if(upload_error || upload_success)
        {
          break;
        }

        if (postLength != 0)
        {
          uint32_t len = gFileFifo.left();



          if (len > postLength)
          {
             len = postLength;
          }
          if(len > sizeof(readBuf))
          {
             len = sizeof(readBuf);
          }
          if(len > 0)
          {

            size_t len2 = server.readPostdata(server.client(), readBuf, len);

            if (len2 > 0)
            {
              postLength -= len2;

              gFileFifo.push((char *)readBuf, len2);


              now = millis();
            }
          }

        }
        else
        {
          rcv_end_flag = true;
          break;
        }
        yield();


      }while (millis() - now < 10000);
    }

    if(upload_success || rcv_end_flag )
    {
      server.send(200, FPSTR(STR_MIME_APPLICATION_JSON), FPSTR(STR_JSON_ERR_0));
    }
    //if((millis() - now >= 10000) || upload_error)
    else
    {

      //Serial.print("len:");
      //Serial.println(gFileFifo.left() );

      //Serial.print("postLength:");
      //Serial.println(postLength );
      if(Serial.baudRate() != 115200)
      {
        Serial.flush();
        Serial.begin(115200);
        // Serial.begin(4500000);
      }

      //Serial.println("timeout" );


      transfer_file_flag = false;
      rcv_end_flag = false;
      transfer_state = TRANSFER_IDLE;
      server.send(500, FPSTR(STR_MIME_APPLICATION_JSON), FPSTR(STR_JSON_ERR_500_NO_DATA_RECEIVED));
    }

    }
  else
  {

    server.send(500, FPSTR(STR_MIME_APPLICATION_JSON), FPSTR(STR_JSON_ERR_500_NO_FILENAME_PROVIDED));
    return;
  }
  }
}

I also add a new endpoint in GET and POST to manage the configuration of BeePrint:

  server.on("/configApp", HTTP_OPTIONS, sendCrossOriginHeader);
  server.on("/configApp", HTTP_POST, postConfigFile, NULL);
  server.on("/configApp", HTTP_GET, getConfigFile, NULL);

It stores a file on SPIFFS that can be used to preserve the configuration of BeeTree UI.

void postConfigFile() {
  DEBUG_PRINTLN(F("postConfigFile"));

  setCrossOrigin();


  uint32_t postLength = server.getPostLength();

  if(postLength > maxPostSize || (postLength <= 0))
  {
    server.send(400, FPSTR(STR_MIME_TEXT_PLAIN), FPSTR("Bad Request, wrong post size"));
    return;
  }



  uint8_t readBuf[postLength];
  DynamicJsonDocument doc(postLength);

  if((postLength > sizeof(readBuf)) || (postLength <= 0))
  {
    server.send(400, FPSTR(STR_MIME_TEXT_PLAIN), FPSTR("Bad Request"));
    return;
  }

  server.readPostdata(server.client(), readBuf, postLength);
//    serializeJson(doc, buf);
//    JsonObject& root = jsonBuffer.parseObject((char *)readBuf);
//
//    root = jsonBuffer.parseObject((char *)readBuf);

  DeserializationError error = deserializeJson(doc, readBuf);


    String postBody = server.arg("plain");
    DEBUG_PRINTLN(postBody);

//  DynamicJsonDocument doc(CONFIG_FILE_HEAP);
//  DeserializationError error = deserializeJson(doc, postBody);
  if (error) {
    // if the file didn't open, print an error:
    DEBUG_PRINT(F("Error parsing JSON "));
    DEBUG_PRINTLN(error.c_str());

    String msg = error.c_str();

    server.send(400, F("text/html"), "Error in parsin json body! <br>"+msg);

  }else{
    JsonObject postObj = doc.as<JsonObject>();

    DEBUG_PRINT(F("HTTP Method: "));
    DEBUG_PRINTLN(server.method());

        if (server.method() == HTTP_POST) {
            if (( postObj.containsKey("server") ||
                postObj.containsKey("preferences") ||
          postObj.containsKey("serverSMTP") ||
          postObj.containsKey("camera")
          )) {

              DEBUG_PRINT(F("Open config file..."));
              File configFile = SPIFFS.open(F("/mc/config.txt"), "w");
              if (!configFile) {
                  DEBUG_PRINTLN(F("fail."));
                  server.send(304, F("text/html"), F("Fail to store data, can't open file!"));
              }else{
                DEBUG_PRINTLN(F("done."));
                serializeJson(doc, configFile);
//                httpRestServer.sendHeader("Content-Length", String(postBody.length()));
                server.send(201, F("application/json"), postBody);

//                DEBUG_PRINTLN(F("Sent reset page"));
//            delay(5000);
//            ESP.restart();
//            delay(2000);
              }
            }
            else {
              server.send(204, F("text/html"), F("No data found, or incorrect!"));
            }
        }
    }
}

Test Upload

The upload process can be managed by curl command like this:

curl -i -X POST "http://192.168.1.164/upload?X-Filename=prova.stl" -H "Content-Type: text/xml" --data-binary "@FBG5_prova.gcode"

And here is the response:

*   Trying 192.168.1.164...
* TCP_NODELAY set
* Connected to 192.168.1.164 (192.168.1.164) port 80 (#0)
> POST /upload?X-Filename=prova.stl×tamp=1635695248382 HTTP/1.1
> Host: 192.168.1.164
> User-Agent: curl/7.55.1
> Accept: */*
> Content-Type: text/xml
> Content-Length: 299092
> Expect: 100-continue
>
* Done waiting for 100-continue
* We are completely uploaded and fine
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Cache-Control: no-cache, no-store, must-revalidate
< Pragma: no-cache
< Expires: 0
< Content-Type: application/json
< Content-Length: 9
< Connection: close
<
{"err":0}* Closing connection 0

Compile mischianti version of the MKS WiFi firmware

Now we must compile the Mischianti MKS WiFi version of the firmware. As described in the previous article, you can upload it directly to the MKS WiFi board or NodeMCU device.

MKS WiFi esp12 programming module connection on BreadBoard

First, you must use the 2.7.4 version of esp8266 core because I continue to use the SPIFFS filesystem like the original version.

Then you must set this value to your Arduino IDE:

And my last build used this set of library

Test env for MKS WiFi with NodeMCU esp8266 on Robin Nano

Activate CORS and DEBUG

To simplify the development of the firmware, I add two define:

#define ENABLE_CORS

that allows you to use an external web interface (not installed on the device), you can get more information by reading the REST tutorial.

#define MKSWIFI_DEBUG

That enable some debug information on a specified Serial

// Define where debug output will be printed.
#define DEBUG_PRINTER Serial1

with this configuration, you can read debug messages on the D4 pin, and you can get more information on this article “WeMos D1 mini (esp8266), debug on secondary UART“.

Generate FileSystem binary file

To get fully working, you must also generate a binary file of Filesystem.

Add verbose output to Arduino IDE

To better understand all processes, we will enable verbose output on our Arduino IDE. You can find these options on File -> Preferences and check Show verbose output checks.

Arduino IDE enables show verbose output.

Now we can grab and reuse console commands.

Prerequisite

For the Filesystem, we can do the same, but first, you need to read the following guides WeMos D1 mini (esp8266), integrated SPIFFS Filesystem.

We will add the data directory to the sketch folder (with some files) and use the plugin to upload.

ESP8266 Sketch Data Upload Menu

In the console, we find the correct command to generate this file.

We can now see a lot of information, including the file’s location and the address.

Using Web Interface or SD to upload

Now with the Web Interface, you can follow these steps to upload

It’s essential to follow these steps because my firmware version needs more resources, and if you upload firmware first, you can’t upload the Filesystem.

MKS WiFi firmware update page

So in the future, if you want to upload a new version of Filesystem, you must upload the older version of the firmware and repeat the process.

You can download pre-compiled firmware of the Mischianti version:

You can download pre-compiled original firmware from here:

  • MksWifi.bin here;
  • If you have firmware like Flying Bear Ghost 5, you can put these files inside the SD, insert It in the printer, restart It, wait until the first process is complete, then continue again to upload the remaining file.

    Thanks

    1. MKS WIFI for Makerbase Robin: boards and how to wiring esp12 & NodeMCU
    2. MKS WIFI for Makerbase Robin: PCB and how to compile & upload firmware
    3. MKS WIFI for Makerbase Robin: communication protocol and Cura plugin
    4. MKS WIFI for Makerbase Robin: firmware upgrade and new Web Socket features
    5. MKS WIFI for Makerbase Robin: BeePrint web interface with Camera on Flying Bear Ghost
    All the code is released under
    Spread the love
    Exit mobile version