QuickSander / ArduinoHttpServer

Server side minimalistic HTTP protocol implementation for the Arduino platform.
GNU General Public License v3.0
23 stars 11 forks source link

Not working from either the Web editor nor the IDE #17

Closed ttimpe closed 2 years ago

ttimpe commented 3 years ago

Hello,

I am building a fan controller script using an Arduino Uno WiFi Rev2 but I always an error regarding a missing Base64 library not being included in ArduinoHttpServer:

StreamHttpRequest.hpp:403:30: error: 'Base64' was not declared in this scope

This happens on both the Web editor and the regular Arduino IDE. I've already tried manually including Base64 in the top of my script.

This is my script:

// ArduinoHttpServer - Version: Latest
#include <ArduinoHttpServer.h>

// #include <Arduino.h>

#include <SPI.h>
#include <WiFi.h>

const char* ssid = "MYWIFI";
const char* password = "PASSWORD";

// UTIL FUNCTIONS

String wrapInQoutes(String input) {
  return "\"" + input + "\"";
}

String boolToString(boolean b) {
  if (b) {
    return "true";
  } else {
    return "false";
  }
}

struct fan {
  int pin;
  String name = "";
  int speed = 0;
  boolean clockwiseRotation = true;
};

struct fan fans[4];

void makeFans() {
  fans[0].pin = 3;
  fans[0].name = "ROOM 1";

  fans[1].pin = 5;
  fans[1].name = "ROOM 2";

  fans[2].pin = 6;
  fans[2].name = "ROOM 3";

  fans[3].pin = 9;
  fans[3].name = "ROOM 4";
}

void setupPins() {
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);

  analogWrite(3, 127);
  analogWrite(5, 127);
  analogWrite(6, 127);
  analogWrite(9, 127);
}

String makeJSONForFan(struct fan *f) {
  Serial.println("makeJSONForFan");
  Serial.println("Making JSON for fan " + f->name);
  String output = "";
  output += "{ ";
  output += wrapInQoutes("pin");
  output += ": ";
  output += f->pin;
  output += ", ";
  output += wrapInQoutes("name");
  output += ": ";
  output += wrapInQoutes(f->name);
  output += ", ";
  output += wrapInQoutes("speed");
  output += ": ";
  output += f->speed;
  output += ", ";
  output += wrapInQoutes("clockwiseRotation");
  output += ": ";
  output += boolToString(f->clockwiseRotation);
  output += " }";
  return output;
}

WiFiServer wifiServer(80);

void setup()
{
  setupPins();
  delay(1000);
  Serial.begin(9600);

  makeFans();
  Serial.println("Starting Wifi Connection…");

  WiFi.begin(const_cast<char*>(ssid), password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(1000);
    Serial.println("Connecting...");
  }
  printWifiStatus();
  wifiServer.begin();
}

void(* reset) (void) = 0; 

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

void updateFan(struct fan f) {
  // PWM from 0-255, 0-126 clockwise, 128-255 counter-clockwise
  // speed should be 0-100
  double calc = f.speed * 127 / 100 * (f.clockwiseRotation * 2 - 1) + 127;
  int c = calc;
  Serial.println("Setting PWM of fan " + f.name + " on PIN " + f.pin + " to " + c);
  analogWrite(f.pin, c);
}

void loop()
{
  if (WiFi.status() != WL_CONNECTED) {
    reset();
  }
  WiFiClient client( wifiServer.available() );
  if (client.connected())
  {
    // Connected to client. Allocate and initialize StreamHttpRequest object.
    ArduinoHttpServer::StreamHttpRequest<1023> httpRequest(client);

    // Parse the request.
    if (httpRequest.readRequest())
    {
      // Use the information you like they way you like.

      // Retrieve HTTP resource / URL requested
      Serial.println( httpRequest.getResource().toString());

      // Retrieve HTTP method.
      // E.g.: GET / PUT / HEAD / DELETE / POST
      ArduinoHttpServer::Method method( ArduinoHttpServer::Method::Invalid );
      method = httpRequest.getMethod();

      if ( method == ArduinoHttpServer::Method::Get )
      {
        if (httpRequest.getResource()[0] == "fans") {
          // /fans
          // check if root
          if (httpRequest.getResource().toString() == "/fans") {
            Serial.println("List all fans");
            // List all fans
            ArduinoHttpServer::StreamHttpReply httpReply(client, "application/json");
            String allFansJSON = "[";

            allFansJSON += makeJSONForFan(&fans[0]);
            allFansJSON += ", ";

            allFansJSON += makeJSONForFan(&fans[1]);
            allFansJSON += ", ";

            allFansJSON += makeJSONForFan(&fans[2]);
            allFansJSON += ", ";

            allFansJSON += makeJSONForFan(&fans[3]);
            allFansJSON += "]";

            httpReply.send(allFansJSON);

          } else {
            // /fans/[0-3]
            String fanIDString = httpRequest.getResource()[1];
            int fanID = fanIDString.toInt();
            if (fanID > -1 && fanID < 4) {
              // /fans/[0-3]/speed/[0-100]
              if (httpRequest.getResource()[2] == "speed") {
                // set fan speed
                String speedString = httpRequest.getResource()[3];
                int newSpeed = speedString.toInt();
                fans[fanID].speed = newSpeed;
                updateFan(fans[fanID]);

              } else if (httpRequest.getResource()[2] == "direction") {
                // /fans/[0-3]/direction
                // set fan direction
                if (httpRequest.getResource()[3] == "clockwise") {
                  // set fan direction clockwise
                  fans[fanID].clockwiseRotation = true;
                  updateFan(fans[fanID]);
                } else if (httpRequest.getResource()[3] == "counter-clockwise") {
                  // set fan direction counter-clockwise
                  fans[fanID].clockwiseRotation = false;
                  updateFan(fans[fanID]);

                }
              }
              ArduinoHttpServer::StreamHttpReply httpReply(client, "application/json");
              httpReply.send(makeJSONForFan(&fans[fanID]));
            }
          }

        }

    }

    }
    else
    {
      // HTTP parsing failed. Client did not provide correct HTTP data or
      // client requested an unsupported feature.
      ArduinoHttpServer::StreamHttpErrorReply httpReply(client, httpRequest.getContentType());
      httpReply.send("");
    }
  }

}

I assume this is an issue in the ArduinoHttpServer since the error mentions Base64 not being included inside it.

QuickSander commented 3 years ago

Hi,

Make sure to install the correct Base64 library as there are several. Personally I use PlatformIO and for that IDEI have included a config file which points to the correct library dependency (lib_deps = agdl/Base64@^1.0.0) for an out-of-the-box experience.

However, this doesn't help you now, try searching for "Arturo Guadalupi's" Base64 library in the Arduino Library Manager. Secondly I will probably try to offer a compile time switch to disable this dependendency and the features coming with it.

aaroned commented 2 years ago

@ttimpe @QuickSander I had a similar issue compiling for an ESP32. Turns out the Arduino core for the ESP32 already has a base64 implementation which seems to conflict with Arturo Guadalupi's Base64 library.

Replacing: #include <Base64.h> with #include <base64.h>

and

const int encodedLength = Base64.encodedLength(combinedInput.length());

char encodedString[encodedLength+1]; // Base64 makes sure _encodedString_ is zero terminated.
Base64.encode(encodedString, const_cast<char*>(combinedInput.cStr()), combinedInput.length());`

with

char* encodedString = base64::encode(combinedInput.cStr());

built fine. Although i'm yet to test the authenticate function.