Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webserver Demo #5

Closed
ajquick opened this issue Jun 22, 2022 · 8 comments
Closed

Webserver Demo #5

ajquick opened this issue Jun 22, 2022 · 8 comments
Labels
discussion Talk about development sample code For coding samples and tests

Comments

@ajquick
Copy link
Contributor

ajquick commented Jun 22, 2022

I have created a branch with a webserver demo:

https://github.com/gbfans/afterlife-lightkit/blob/webserver/SOFTWARE/Webserver.ino

Currently the code will do the following:

  • Start the access point with the name "Afterlife " + MAC ADDRESS
  • Start a webserver on board the ESP8266
  • Start a DNS server (255.255.255.0)
  • Set a static IP address (10.10.10.1)
  • Start the LittleFS file system (doing nothing currently)
  • Initialize the Eeprom (no data stored currently)

Now it is supposed to start the DNS server and handle all requests to the internet and then display a Hello World page for everything. However it does not currently do that.

Accessing through http://www.msftconnecttest.com/redirect or the device's static IP of http://10.10.10.1/ does show the "Hello World" page.

@ajquick ajquick added discussion Talk about development sample code For coding samples and tests labels Jun 22, 2022
@prodestrian
Copy link
Collaborator

prodestrian commented Jun 24, 2022

Finally picked up an ESP8266 today so I can start testing out some of these features and make some progress again.

After getting the Arduino IDE configured and successfully uploading the Blink sketch, I tried this one out.

After uploading I could see the Wifi network:
2022-06-24_16-27

When I connected my phone to this network it instantly opened a Connectivity Check with Sign In prompt, which displayed the "Hello World" page (my Android phone thought it was a hotspot which required a login).

For me it actually does handle all requests to the internet. I navigated to http://myfakedomain.com and received the Hello World page.

But if I try accessing a site I've visited previously, I get a CONNECTION_REFUSED error because 99% of those sites are on HTTPS (usually with HSTS-enabled, which my browser remembers and won't allow me to connect via HTTP). So my browser tries to connect to port 443, but the webserver is only listening on port 80, and so I get the error.

There's no real way around this as it's a key part of HTTP security, but I don't think it's a problem for us.

Just for the fun of it, I modified the sketch to see if I could perform some requests with it:

#include <Arduino.h>

#include <FS.h>
#include <LittleFS.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <EEPROM.h>

const byte        DNS_PORT = 53;
IPAddress         apIP(10, 10, 10, 1);
DNSServer         dnsServer;
ESP8266WebServer  webServer(80);

#ifndef APSSID
#define APSSID "AFTERLIFE " + WiFi.macAddress()
#define APPSK  "ghostbusters"
#endif

String responseHTML = "<!DOCTYPE html>"
  "<html lang=\"en\">"
  "<head>"
    "<meta charset=\"utf-8\">"
    "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
    "<title>Hello World</title>"
  "</head>"
  "<body>"
  "<h1>Hello, World!</h1>"
  "<form action='/trigger' method='post'>"
  "<input type='submit' name='action' value='On'>"
  "<input type='submit' name='action' value='Off'>"
  "</form><br>"
  "</body>"
  "</html>";

void setup() {

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  WiFi.softAP(APSSID, APPSK);

  dnsServer.start(DNS_PORT, "*", apIP);

  webServer.on("/trigger", HTTP_POST, [] () {
    String inputMessage;
    if (webServer.hasArg("action")) {
      inputMessage = webServer.arg("action");
      if (inputMessage == "On") {
        digitalWrite(LED_BUILTIN, HIGH);
      } else if(inputMessage == "Off") {
        digitalWrite(LED_BUILTIN, LOW);
      }
    }

    webServer.sendHeader("Location", String("/"), true);
    webServer.send ( 302, "text/plain", "");
  });

  webServer.onNotFound([]() {
    webServer.send(200, "text/html", responseHTML);
  });
  webServer.begin();

  LittleFS.format();
  Serial.println("Mount LittleFS");
  if (!LittleFS.begin()) {
    //error
  }

  EEPROM.begin(512);

}

void loop() {
  dnsServer.processNextRequest();
  webServer.handleClient();
}

This sketch displays an On/Off button which controls the built-in LED, it worked very well during testing.
I'm unsure what methods others use to keep this code clean, rather than dynamically generating huge slabs of HTML inside the sketch. It would be great to at least split them out into separate files. We could also have a single HTML page and do everything with Javascript/AJAX, but I'd need to dig into this further to see if it's viable and within the device's memory limits (we wouldn't want to use up all the memory on what is essentially the least-important feature).

Edit: I need to have a play with this: https://github.com/plapointe6/EspHtmlTemplateProcessor
Maybe starting with this tutorial: https://randomnerdtutorials.com/esp8266-web-server-spiffs-nodemcu/

@ajquick
Copy link
Contributor Author

ajquick commented Jun 24, 2022

Can you push your code to the webserver branch? Getting interactions is the next step, and its something I can focus on doing if you would prefer. I just need API end points to save config data and trigger events.

But if I try accessing a site I've visited previously, I get a CONNECTION_REFUSED error because 99% of those sites are on HTTPS (usually with HSTS-enabled, which my browser remembers and won't allow me to connect via HTTP). So my browser tries to connect to port 443, but the webserver is only listening on port 80, and so I get the error.

This makes sense. Also because on sites previously visited the DNS is cached on your device, so it's probably trying to connect to whatever IP that isn't the ESP8266.

Edit: I need to have a play with this: https://github.com/plapointe6/EspHtmlTemplateProcessor
Maybe starting with this tutorial: https://randomnerdtutorials.com/esp8266-web-server-spiffs-nodemcu/

These both use SPIFFS as the file system. I had planned on going with LittleFS since I think it is a little easier to deal with loading files on to the ESP8266. If you have any insight into that, let me know. Basically I think LittleFS can just have a "data" directory with raw files (index, js, css, jpg.. etc) that can be accessed or fed directly instead of having things in the Arduino code.

@prodestrian
Copy link
Collaborator

Yep, I'll push my code shortly 👍

These both use SPIFFS as the file system. I had planned on going with LittleFS since I think it is a little easier to deal with loading files on to the ESP8266. If you have any insight into that, let me know.

After a bit of research, it looks like SPIFFS is deprecated/unsupported anyway, plus LittleFS is apparently more performant. So let's stick with LittleFS:
2022-06-25_11-44
https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#:~:text=SPIFFS%20is%20not%20actively%20supported,times%20faster%20for%20most%20operations.

I can't find any HTML template libraries which support LittleFS, but I don't think that's a dealbreaker anyway (we're not going to building anything too complex here).

I was able to convert the Webserver demo to store the HTML file in LittleFS, the only catch is that I couldn't get it working with ESP8266WebServer so I had to swap out for ESPAsyncWebServer (which also requires installing ESPAsyncTCP).

I'll commit what I have so you can try it out: #9

@prodestrian
Copy link
Collaborator

prodestrian commented Jun 25, 2022

Now that I've got my hardware connected (See #7) I tried to perform an integration test with the Webserver code and my Neopixel code.
Everything connects and I can even click the HTML buttons to change my animation speed.
But then the Wifi network drops out, within about 10 seconds. The LED animations continue fine.

I'm currently powering the Neopixels directly from the ESP8266, I thought maybe the current draw was too much for the Wifi. But even after disconnecting the Neopixels entirely the Wifi still drops out.

So I commented out my animations and left just the webserver (and dependencies), the Wifi stays up fine. Next thing I tried was removing the animations and just setting the colour of one of the Neopixel strips based on the button presses (no timers etc, just the Adafruit Neopixel library). This still dropped out unfortunately. So pretty much ruled out my animations and the Timers, I think it's Neopixels interfering with Wifi.

I jumped onto the Adafruit GitHub and searched for ESP8266 and found this Issue:
adafruit/Adafruit_NeoPixel#176

That led me here: https://forum.arduino.cc/t/interrupting-the-neopixels-help-needed/495593

One of the problems in that the NeoPixel library temporarily disables all interrupts when issuing data, then re-enables them when done. Since a lot of those functions are essentially always updating the LEDs, well then you don't have room much for anything using interrupts.

We're not be able to use Wifi and the Adafruit Neopixel library at the same time.

What alternatives are out there?
https://github.com/Makuna/NeoPixelBus/wiki/Library-Comparisons
NeoPixelBus seems to have been designed for exactly this reason. I brought it into my sketch with minimal effort, but it looks like it unfortunately requires you to use specific GPIO pins on the ESP8266 (it ignores the pin you configure). This won't work if we're already committed to specific pins on the PCBs. Also doesn't seem to like running multiple Neopixel strands at once.

So, next up I tried FastLED. It took a significantly bigger rewrite to get up and running. But it mostly works (with a couple of weird hacks that I found others had to use on the ESP8266), and the logic of my original animations translates very pretty easily. In fact I actually like some aspects of it more than the Neopixel library.

I now have a working demo with the Cyclotron LEDs and Webserver/Wifi. I can control the speed of the Cyclotron over Wifi:
https://www.youtube.com/watch?v=rnBNd0qfW8Q

There are still some random glitches/flickering in the Cyclotron LEDs though. If I disable Wifi it runs smoothly, so there's potentially some adjustments/optimizations to be made there.
These 3 lines specifically cause the LED flickering:

WiFi.mode(WIFI_AP);
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
WiFi.softAP(APSSID, APPSK);

I've barely scratched the surface of the FastLED documentation so I don't know what configuration/troubleshooting options we have available.
Also I'm not (currently) using a 3.3V logic level shifter, I forgot to pick one up yesterday so it'll be another week before I can get one. It's possible that's causing the flickering, very hard to tell though.

If it's not a solvable problem, then that unfortunately rules out "Party Mode" 🤣

Disabling Wifi

I just tried adding some code to disable Wifi (by clicking on a button on the HTML page), and although it does switch it off I can't seem to re-enable it. Apparently it's possible, but I can't tell if it's Wifi that's failing, or DNS, or the WebServer. Need to read some more documentation.

Update: Disabling Wifi does fix the flicker, in fact I notice that every time I click on a button while Wifi is enabled, the LEDs flicker more! So it must be whenever a Wifi packet is received it interferes with the Neopixels.
So this code does work:

void startWifi() {
    WiFi.setSleepMode(WIFI_NONE_SLEEP); //Put this at the top of the setup function.
    WiFi.mode(WIFI_AP);
    WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
    WiFi.softAP(APSSID, APPSK);
}

void stopWifi() {
    WiFi.disconnect(true);
    WiFi.mode(WIFI_OFF);
    webServer.end();
}

It's getting late, but I'd like to connect it to a button and see if I can toggle Wifi on/off. So users could switch it on, change some settings, switch Wifi off again, and then use their Pack as normal.

@ajquick
Copy link
Contributor Author

ajquick commented Jun 25, 2022

Regarding the flicker, are there any wires or large metal surfaces (ground planes) near the Wi-Fi antenna? Maybe try moving the ESP8266 to see if the condition improves?

Perhaps a good idea to check to see what Wled has done because I suspect they have tackled all these issues. They already use the Async webserver, LittleFS, FastLED.. etc. So it is definitely possible.

https://github.com/Aircoookie/WLED/blob/main/wled00/wled.h

@prodestrian
Copy link
Collaborator

prodestrian commented Jun 26, 2022

It's plugged into a breadboard sitting on a wooden desk, I don't think there's any interference.

I'm installing WLED to see if I have the same problem, but I'm feeling pretty confident it's a hardware issue now.

I also ordered some bidirectional logic level converters, I did find a 74LVC245 in my collection but it seems to be 5V to 3.3V, not 3.3V to 5V which is what I need (unsuitable for Neopixels). So it'll be at least a few days before that arrives.

UPDATE: WLED works perfectly, so unless there's something different about using the device as a SoftAP vs a Wifi client, maybe it isn't hardware. That's good, I can see if there's any solutions we can borrow from wled 👍

@prodestrian
Copy link
Collaborator

prodestrian commented Jun 26, 2022

I've been trying to decipher the code from WLED but it's so heavily abstracted that I just can't understand it. I did find a few small configuration options which seemed to relate to ESP8266 but none had any effect. The flicker remained when I brought it into my sketch.
Eventually I found this post: FastLED/FastLED#849
which linked to this commit: srwi/FastLEDHub@54bbaf1

I copied it into my sketch and 💥 no more flickering. My guess is that WLED isn't affected because they're doing all the LED communication themselves at the lowest (pin) level (which is why there's no FastLED.show() anywhere in their code).

It's an ugly hack but it should be enough to keep us going, I'll include some comments so we can periodically check on the original issue and see if someone resolves it.

Next I just need to reconnect the PowerCell and make sure I can still run both strips at the same time 🤞

@prodestrian
Copy link
Collaborator

The demo of the webserver is completed (as documented in #10) so I believe we can close this too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion Talk about development sample code For coding samples and tests
Projects
None yet
Development

No branches or pull requests

2 participants