Sunday, September 29, 2024

ESP8266 Captive Portal, Static Serve, and Websockets

While working on a toy for my dog, I wanted to set up an AP with captive portal. This took a little bit because a lot of examples out there were a bit out of date and did not work properly. The main issue was that the CaptiveRequestHandler class was not specifically handling Android and iOS captive handler endpoints. 

I changed the class like this and it worked fine: 

class CaptiveRequestHandler : public AsyncWebHandler {
public:
  CaptiveRequestHandler() {}
  virtual ~CaptiveRequestHandler() {}

  bool canHandle(AsyncWebServerRequest *request){
    String url = request->url();
    return (url == "/generate_204" || url == "/hotspot-detect.html");
  }

    void handleRequest(AsyncWebServerRequest *request) {
        if (!request) {
            Serial.println("Received null request");
            return; // Return early if the request is null
        }

        // Check for specific requests (e.g., Android's `/generate_204`)
        if (request->url() == "/generate_204" || request->url() == "/hotspot-detect.html") {
            // Redirect to the captive portal (ESP8266’s IP)
            request->redirect("http://192.168.4.1/index.html");
        }
    }
};


The canHandle was modified to only handle these methods, otherwise to return false. This is important because later we want to handle requests with other handlers. 

That said, I also added a static serve handler:

WiFi.softAP(SSID);
dnsServer.start(53, "*", WiFi.softAPIP());
server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER);//only when requested from AP
server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html");

This meant my index.html page would request other assets (images, css, js) and they would be served. One thing to note is that in order for this to work on a platformio project, you need to update your platform.io config with your (filesystemboard_build.filesystem = littlefs)

Finally because we are allowing handlers, we can setup the web sockets. 

// Set up WebSocket
ws.onEvent(onEvent);
server.addHandler(&ws);  // Add WebSocket handler to the server

// Start the server
server.begin();



Friday, September 13, 2024

Slightly Painful - Painless Mesh for ESP32

While working on a mesh networking project, I decided to give Painless Mesh a try. 

I ran into whole bunch of issues in PlatformIO for some reason, so I resorted to using ArduinoIDE 2. 

The first weird thing was that I got a message saying: 

Failed to install library: 'PubSubClient:2.8.0'.

Error: 2 UNKNOWN: destination dir C:\Users\CorrLabs\Documents\Arduino\libraries\PubSubClient already exists, cannot install

The solution to this was just to manually delete the folder and reinstall the library. For some reason there was a library already downloaded, but Arduino IDE could not utilize it.


Then I ran into this one:

wifi.hpp:49:14: error: 'class WiFiClass' has no member named 'setAutoConnect'; did you mean 'setAutoReconnect'?

Fortunately, I found a comment by a person named luckymatt who had the answer to this. Basically the problem is just with compatibility changes between versions. 


At this point, I was able to compile and flash my ESP32-WROOM32 dev board with the Painless Mesh MQTT example.


References:

https://forum.arduino.cc/t/error-with-wifi-hpp-when-compiling-painless-mesh-code/1248608/13

Sunday, June 2, 2024

Visual Studio Installer: ERROR: The system cannot find the file specified - following system restore

Problem: 

A long story short, a bad USB adapter killed motherboard USB headers. The system was old enough that buying a new CPU/motherboard would be as much as buying a used motherboard. I decided to do a new build, and with a fresh install my OS. While installing Visual Studio Community 2022, I found that the installer would download files, but then die when trying to perform the install. I had earlier had a BSOD issue with a PCI card, and ended up running a repair on my system. This messed up a lot of my just installed applications including Visual Studio. Oddly, the installer did not list a specified file, the rest of the error popup was blank.


Solution: 

After researching their cleanup tool (which you can only get if you successfully installed VS) and reading a couple SO posts, I decided to just try something. I renamed my application directories for 

    C:\Program Files (x86)\Microsoft SDKs 

    C:\Program Files (x86)\Microsoft Visual Studio 

and tried the installer again. This time it worked. 

Keep in mind this will likely mess with any settings you have already in place. 



Monday, April 29, 2024

Addressable LED Strip Odd Colors with Arduino | Weird Behavior

I was trying to run some test code using a strip of addressable LEDs and my Arduino, but every time I ran the program, I got odd colors and the last LED color was green. Sometimes I would get a stronger color in each LED - especially when trying to set them to all white. In my case it was Red, Green, Blue (repeating 1 time) then all the other LEDs were unlit.


It dawned on me (later than I would have liked) that the order of values was wrong for the LED strip I was using (you can visibly see the large White diode in each white square). I had initialized my LED strip (using NeoPixel) to NEO_GRB instead of NEO_GRBW as my strip has a dedicated white LED. My major mistake here was that I thought I had a strip of WS2812B LEDs but really they were SK6812RGBW LEDs. 


Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRBW + NEO_KHZ800);

void setup()
{
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();  // Turn OFF all pixels ASAP
  strip.setBrightness(MAX_BRIGHTNESS);
}

void loop()
{
auto color = strip.Color(255, 0, 0, 255); //  Optional 4th param is White
  for (int i = 0; i < strip.numPixels(); i++)
  {                                
    strip.setPixelColor(i, color); //  Set pixel's color (in RAM)
    strip.show();                  //  Update strip to match
    delay(50);                     //  Pause for a moment
  }
}

Friday, March 8, 2024

SiteGround SSH Login Trouble - Permission denied (publickey).

Problem:

Working with a company that uses SiteGround for hosting, we setup SSH access on the website using keys. The SiteGround system forces a specific SSH passphrase for your key pair and it appears to be randomly generated, which is fine and considered fairly secure to my knowledge. 

After setting up SSH config on my local machine and leaving things for a while, I came back to find that I could not login anymore. I confirmed my access should still work and that nothing has changed with the keys or passphrase but I continued to get: 

Permission denied (publickey).


Solution:

New solution: try a pass phrase with limited special characters. This does require you to setup a new ssh key through the website, but has ultimately solved my issue. My original solution seemed to be that somehow logging in was associated with when the passphrase would work and when it wouldn't. This is not the case. I also talked to support but they were only able to verify that my IP address was not being blocked while debugging the issue. 

Original solution: For some reason, SiteGround requires you to log back in on the their website before you can login with SSH. If you are already logged in, then you may need to log out and back in. As a guess, I think this is probably just a way they have chosen to try and combat potential bad actors, but it certainly has a lot of friction to it. 



Wednesday, January 3, 2024

Process Explorer - DLL Inspection

 I've been working with a DLL I got that doesn't have very great documentation. After trying a couple different things (ILSPy, and custom python to load and print callable functions) and all failing, I asked the great chatGPT. It suggested Process Explorer. 

I started my application, then searched for the DLL. Once I found the DLL, I was able to right-click and examine it's properties. This loaded a window with two tabs, Image and Strings. To be honest, I'm not sure off the bat what those mean, and the data on each tab seemed to be the same as the other at quick glance, but I was able to find functions I knew existed along side functions that I was not aware of. 


Exercise caution when calling any undocumented functions in your DLL, they may produce undesirable or event irreversible results.

Tuesday, December 26, 2023

Edit-as-you-go Sound Recorder

My friend, Mason, is an actor in film, stage, and voice projects. One of his enjoyed past times is to record audio books. Y'know, long ones, the ones in the public domain (his still sound great though). All from the kindness of his heart. The problem is that his typical workflow included recording long takes often with restarts or variations. Then, when he went to edit the hours and hours of audio, it would take him a really long time to narrow things down to the ones he really wanted. All this and he still had the other audio processing he likes to do before he publishes. 

As we were hanging out, I had the idea that one could substantially cut down on time if you make the decision about selections as you record them. More often than not, he has a good ideas what recording segments he thinks will work well. This is when I got to thinking about the Edit-as-you-go Sound Recorder (I'll call it EAYG). The idea was simple, write a program that would record your microphone and then when you knew you had something you liked, you would hit a keyboard shortcut and it would automatically be stored for you. Another benefit is that each clip already has a natural cutting point by virtue of being a self-contained clip or segment. Using ChatGPT a bit (haven't done much with sound in Python), and after putting things together for a couple hours, I had a working version of the program with managed memory buffers, recording flow, and even restoring your last recording if the program crashes mid-take. 

The program records audio at 96kHz 32-bit. This could be easily changed in the code, and maybe from a preference menu or something. 

Another note, Mason is always inside his recording booth, and not next to his computer. Using a simple wireless keypad, and the program shortcuts, he can trigger whatever action he wants to have happen to the clip and get audible confirmation through his headphones. 

You can checkout Mason's stuff here:

Mason Willard - Stage, Film, and Voice Actor
Youtube: https://www.youtube.com/@_roscius
Email: [email protected]





Instructions

Before recording, choose session directory. This directory will be the location of one or two more directories after you finish recording your session (based on good/bad takes).

Next, choose your recording device or interface.

To begin recording, start the session (F10). Once the recording has started it is now recording audio. When you are happy with the take, click Finish Good Take (F11).
If you don't like the take, click Finish Bad Take (F12).
If you are not sure about the take, click Replay Last Take and you can listen to the take on repeat, then choose Finish Good Take or Finish Bad Take.

Choosing Finish Good Take or Finish Bad Take, saves the audio segment in a respective folder, and then begins recording again automatically. 

When you are done with the session, click End Session (F10). The last segment of recording prior to the session ending will be discarded.

Your good takes will all be in a folder called /recorder-keep and the rejected audio files are in a folder called /recorder-discard. All files have been named using timestamps so they are sortable. The location of these folders can be selected prior to starting a session.

Keyboard Shortcuts

These can be changed in the code easily enough. The reason behind these was specific to the original use case of using a mini wireless keyboard to trigger recordings from inside the recording booth.

Assembly in Audacity

For quick assembly in Audacity, you can select all your good takes and drag them into a new session. Next, select them all and choose Tracks from the top menu. Then choose Align Tracks -> Align End to End.




Also, it may be helpful to turn on ripple edit so as you modify each take, the other audio files don't fall behind. You can enable this by going to Edit -> Preferences and the go to Track Behaviors and check the box "Editing a clip can move other clips"








More Help or Desired Changes

The code is available as is. If you find bugs, please submit them on GitHub and I will address them as I am able and time permits. In the event you would like bugs fixed sooner, customizations, or personal help setting up and using the program, I can be available to help at my hourly rate. 

Repo: