-
Notifications
You must be signed in to change notification settings - Fork 0
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
Configuration and default patterns #10
Comments
I uploaded a very basic test script, though currently it is outputting 'null' to the serial port. https://github.com/gbfans/afterlife-lightkit/blob/configuration-testing/SOFTWARE/config_test.ino |
Finally finished work for the week so I can get back into all this. |
I've been struggling with the code all day (and part of yesterday), got it this far: #11 It's a start, but there's quite a few roadblocks. I'm hitting up against my C coding knowledge, I know how I want to structure things but I struggle to know how to write it in C. The |
Progress UpdateAfter some additional proof of concept work, I have scoped out a potential way to organise the Configuration. PresetThis is the highest level of configuration, which determines which combination of settings should be used.
Additionally users will be able to create their own Presets and import/export/share them. A preset should be contained within a single JSON file. We can include multiple JSON files on the filesystem (instead of trying to squash everything into one Light / ElementAlso known as the Light Strips, these are the actual hardware connected to the board.
Configuration involves mapping settings to each of the 3 Light Strips inside each Mode, and for each State. StateSimply put, the current State of the Lights:
NOTE: This is unrelated to the Control State of the Pack (as sent from the Soundboard). Our main application loop (in NOTE: For simplicity, Colors will be excluded from States and will only apply to the Modes (for now). So it will not be possible to assign different Colors for different States on the Pack, eg "When firing in Proton Mode, make the Cyclotron purple, but switch back to Red when idle". ModeThese are different options within each preset, for example the Video Game (TVG) modes. NOTE: The Wand cycles through 8 different modes:
However the Soundboard doesn't send this to the lightkit, only the color. So both Slime Tether and Slime Blower are "GREEN". We can re-map the colors to our own naming convention, for example:
And then allow choosing/assigning the Color as part of the Preset. So if a user wanted their Stasis Mode Purple instead of Blue, they could configure this easily. The Color is assigned individually to each lightstrip/Element. Potential JSON SchemaNOTE: This requires a little more planning. JSON Files could/should be given the name of their Preset, eg
We can differentiate between default/locked presets and user custom ones by adding a If possible, a checksum should be included in the JSON file (similar to PHP Composer Lockfiles) so that we can easily check for corrupt data before allowing imports, but this will add more complexity to the UI. So, to replicate this code in Configuration (displaying a blue Tetris animation which speeds up over 3 seconds on the Power Cell): We would have JSON which looks something like this: {
"title": "1984 Counter-Clockwise Mode [GBFANS]",
"checksum": "ca50190ac4a3943ba5c17e566a4febb2",
"author": "GBFans.com",
"description": "Classic 1984-style Pack Animations, featuring a Counter-Clockwise Cyclotron (as seen in certain scenes on the Venkman/Zeddemore Packs)",
"modes": {
"proton": {
"powercell": {
"color": {
"red": 0,
"green": 0,
"blue": 255
},
"states": {
"startup": {
"effect": "tetris",
"startSpeed": 25,
"endSpeed": 5,
"duration": 3000,
"reverse": false
}
}
}
}
}
} Ideally we will want to parse each JSON State configuration into a class which can be more easily passed through the application. This would save us from having to perform lookup logic on nested values. InitializationOn a blank device there will be no initial configuration files. Although it would be easy enough to upload them as each device is being flashed (before dispatch to customers), ideally this should be an automated process. |
Additional Configuration NotesFurther to the above, we will still require a separate We should be able to abstract the hardware out further too, so that our Lights class simply has 3 LED strips defined of varying lengths, each one is converted to an FX class. As we set States in the Lights class, we use Configuration to tell each FX instance what to do (animation, speed, etc). This should allow us to remove a significant amount of code. We could (in theory) abstract our Light class even further, so that we don't require individual functions for each State. |
Configuration Server Progress UpdateI attempted to use WifiManager in this project however it causes weird flickering of the LEDs (the first LED in each strip flashes randomly). I have attempted to work around this but it might be an issue at the hardware level. This suggests it's an issue with either our Lights or Control classes (either writing the LED data, or reading from the GPIO pins). After some trial and error it seems to be our So, I completely disabled the Cyclotron/NFilter LED strips and FX instances but the same issue still occurs (in case it was due to having multiple timers running). I then disabled the check from the ramp instance, still no luck. I removed the updateBrightness call so the FastLED write ( It must be a FastLED + Wifi conflict, which gives me something to look for: Interestingly it looks like FastLED 3.6.0 was released 2 weeks ago, I was still running 3.5.0. It says there have been improvements, so I will upgrade: Someone in one of the threads suggested removing the I then found I added the following web server endpoint: // Send a GET request to <IP>/get?message=<message>
server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
String message;
if (request->hasParam(PARAM_MESSAGE)) {
message = request->getParam(PARAM_MESSAGE)->value();
if (message == "idle")
{
lights.setState(IDLE);
} else if (message == "wifioff") {
// Turn off Wifi
WiFi.mode(WIFI_OFF);
} else {
lights.setState(INACTIVE);
}
} else {
message = "No message sent";
}
request->send(200, "text/plain", "Hello, GET: " + message);
}); When connecting to the device over Wifi this URL lets us change the pack state from IDLE to INACTIVE and back again. This is working well, the lights are updating without flicker, however there is a moderate amount of lag (more noticeable on the Powercell). So I included a server.end();
WiFi.softAPdisconnect(true);
WiFi.mode(WIFI_OFF); It lags at first, but after a few seconds it seems to improve. So the next test is to have the Wifi switched off at startup and go immediately into an idle animation. This seems to be working, I can turn Wifi on/off, and I can still access the webserver even if it is initialized late: I experienced unusual behaviour, I switched the animation state over the webserver and it seemed to cause the device to restart. I have added a serial output to detect this and I don't believe this is actually occurring (more than likely it's my Chrome browser doing pre-fetching, so it hits the URL even though I haven't actually clicked "enter"). Starting Wifi causes the LED animations to pause briefly. If Wifi fails to connect it can be a 10 second pause. I don't believe either of the above are problems. However turning off Wifi after several attempts did seem to cause a fatal exception: |
Wifi Access PointThe above demo currently connects to my home WiFi (which occasionally fails to connect). We would prefer to have this as an access point instead. So I will bring in some of the demo code we already have from #5 and get the webserver working as a Wifi hotspot. #ifndef APSSID
#define APSSID "GBF-LK-" + WiFi.macAddress()
#define APPSK "ghostbusters"
#endif However:
I'm certain we had this working previously. So I uploaded the previous webserver demo code to see how this behaves, and it still refuses to connect from either device. I uploaded our sketch and can see the SSID:
However I still couldn't connect from either device. It looks like the DNSServer needs to be always running, regardless of whether WiFi is active. I was able to trigger the WiFi and connect from my laptop, and access the demo page. I disconnected the WiFi and tried to power up the pack. The signals were received but the lights did nothing. I restarted and still can't get the lights to switch on when I power up. The default blink sketch works fine, the ESP8266 seems to work. I disconnected the Arduino Nano (which I'm emulating the soundboard from). So there might be a hardware problem with the GBFans board. I will break out my multimeter and try to debug. EDIT: It turned out to not be a hardware issue, it's due to the LittleFS being erased (and we don't have any fallback for JSON configuration files yet, so it fails). I can continue from here now. |
Just a reminder with the hardware, make sure the output enable is active on
the level shifter. The lights won't work without it and may be why it's not
working with the generic demo code.
…-AJ Quick
|
You're absolutely right, I thought I still had that in the demo code but I had reverted it for another project. My With debug mode disabled, the LED animations are completely smooth now. There's some minor lag when WiFi has been activated, but as soon as WiFi is switched off again it runs fast. So if the lag only appears while the user is using WiFi then I don't think there's any big issues here. I'm going to leave it running for an hour or so and see if there are any exceptions/crashes or memory leaks. Then I can pick back up on the web UI portion of this task (which I started last night, so far it's going well). |
Configuration Simplification and RefactorTo reduce the amount of code needed in each configuration option (and the number of options exposed via the UI) I have begun simplifying the ConfigManager, FX, and Light classes. We no longer need separate RGB values for each lightstrip, we can use Hex Color Codes as supported by the CRGB class:
This sample output confirms that the This is the first time we have confirmed that colours can actually change in 'realtime' on an existing FX instance, so I have modified the firing code to change colour from red to green and back again. This works fairly smoothly, which means MODE changes should work when I finish implementing them (proton, slime, stasis, meson). My next requirement is to translate string 'effect' values into a usable ENUM value, ie "tetris" into |
Light Preset & JSON Configuration Progress UpdateAfter hours of issues with memory leaks and JSON parsing problems, I finally have working code to read values from JSON files and convert them into usable properties. Example JSON config file: {
"modes": {
"proton": {
"color": {
"powercell": "0x0000FF",
"cyclotron": "0xFF0000",
"nfilter": "0xFFFFFF"
},
"states": {
"idle": {
"powercell": {
"effect": "SPINNING"
},
"cyclotron": {
"effect": "CYCLING"
},
"nfilter": {
"effect": "OFF"
}
}
}
}
}
} In this case I was able to modify the powercell effect from I will need to add some sanity checks to ensure that invalid/missing values in the JSON files are handled gracefully, at the moment this causes a fatal exception (the device crashes and restarts itself constantly). I have committed the changes I made so far as the application is in a semi-working state right now and I can build on this fairly easily. Currently WiFi is not working though, I can't connect from my laptop or my phone. I rolled back to the WiFi configuration branch (which I'm 95% sure was working at the time I pushed the changes), and this isn't working either. UPDATE |
I just downloaded PlatformIO on VS Code. Is there a particular branch you want me to follow along with? I tried one of the more recently updated branches and didn't get any Wi-Fi to show up or lights. |
@ajquick For debugging I recommend changing You can use the Arduino IDE to upload the files if that's easier, or via PlatformIO: # Upload JSON file from `/data`
pio run --target uploadfs
# Build/Upload firmware
pio run --target upload You can also access the Serial Monitor via: pio device monitor --eol=LF (You may not need the Let me know if you have any issues. |
Here is what I'm seeing so far. (I don't have a way to control the switches, so my lights are not being tested right now). I have turned on the webserver and see the Wi-Fi, but I am unable to connect on either my phone or computer. It just immediately kicks me out and says unable to connect. One thing that I will need to do is test the on-off-on-off-idle function with the actual sound board. There is a possibility it does the start up and then waits for start up to finish before going into shut down. I don't think it is an immediate on-off-on-off like you would do with the switches. |
That's useful information, thanks! I think I'll need to revisit the WiFi, it works semi-reliably from my Ubuntu laptop but doesn't work at all from my Android phone. So I'll put together a simple test sketch and get that working smoothly on the hardware, then add the lights back in one piece at a time (making sure it works at each step). It might mean swapping out a dependency or two. As far as the WiFi activation sequence it's pretty easy to adjust the code for that, so currently it's: This can be changed to: It means changing this line here: if (controls.isSequenceMatch("1:14:1:14:1:14:0")) { We can also add an "or" to this, in case someone tries to trigger WiFi while their pack is already idle (so the sequence might be slightly different), or if somehow the soundboard is sending different combinations of signals. |
I will definitely check the sound board and verify what we get exactly. Is there any time frame it checks for the sequence or is it always just a sequence irrespective of time? This is almost never going to happen during normal operation:
But this might if someone turns on the pack without firing twice:
|
At the moment there's no time limit, but because I'm not waiting for an "Idle" state between each cycle it means you have to trigger Powerdown while it's still in Startup. As you say, if the soundboard forces you to wait for Startup to finish (and then sends a quick Idle signal before going into Powerdown) it means what I have above won't work. I've been at events where I've cycled my pack on/off multiple times without firing, but it's always with minutes/hours of Idle between those powercycles. That's why I was hoping that Powerdown during Startup would be a good way to do this, it seems like you'd have to do it intentionally. But we'll see what the soundboard does, even a single frame of "Idle" signal would stop this from working. We'll need a timer to automatically deactivate WiFi so I'm more than happy to add another timer for the signals (ie "last signal received"). This would clear the history if more than (let's say 30 seconds) has elapsed since the last signal. Could probably even make it 10 seconds, honestly we're not using the history feature for anything else anytime soon anyway, unless we add a different sequence for quickly changing Presets (ie toggling the pack between Classic & Afterlife modes). |
One thing to consider is also standalone mode.
So Wi-Fi mode might be need to be turned on two different ways. I don't think standalone mode is active right now because the lights should turn on without anything connected. |
We have the framework for supporting standalone mode but I haven't implemented it yet. We can turn on WiFi whichever way you think is best, as long as it's not on by default during startup because it blocks everything for several seconds (even when I use supposedly "asynchronous" code). In the meantime, this weekend's priority is:
As far as remaining tasks:
I believe that would be enough to make this shippable (v1.0.0 release) but it's possible I'm missing things here. I don't know if we have full support for venting yet, there's some soundboard signals documented that I don't fully understand yet (automatic vs manual vent for example) so that may require some additional handling once you've connected it up to the soundboard and recorded how it's behaving. |
I've just burned another I've tried 5 different demo ESP8266WiFi sketches from various libraries. I've tried changing the channel. I've tried removing the password. I've tried powering the board from a high-current USB powerbank. I've tried changing the configuration in the Arduino IDE (eg CPU Frequency etc). I'm assuming the GBFans board is actually a "LOLIN (WEMOS) D1 Mini (Clone)"? (That's what I've always been setting the Arduino IDE to). I've also tried downgrading various packages to older versions. I've trawled through 30+ different support threads with zero success here. I'm actually not convinced the WiFi access point has ever worked properly on my GBFans board. I'm going to put a pin in WiFi for now but this looks like it's going to be problematic if I can't even get a demo sketch connecting from my phone. I don't think I can fix this one on my own. Edit: Here's the settings I'm using in the Arduino IDE for the GBFans board. I don't know if they're correct, but it's what I based the PlatformIO configuration on too: Edit: I also tried my old Samsung phone, same issue. It finds the AP, it tries to connect, then immediately disconnects. Nothing appears in the debug logs. Edit: I installed WLED to the device. The Edit: I downgraded to ESP8266 Edit: One last thing, I tried installing AutoConnect. Again, works perfectly fine from my Ubuntu laptop, doesn't work from my phone. I tried several of their FAQ fixes (including changing the channel) but nothing worked. I'm convinced there's a hardware issue going on here, but in the literal hundreds of forum posts I've read today I can't find anyone else who's had exactly this issue. |
My thoughts for configuration is as follows.
A JSON file is created that contains a standard set of configuration options. This file can be stored in the file system and will be able to be uploaded through the web app. This JSON file can be manually edited, but it can also be updated via GUI in the web app if need be. When config settings are changed, the JSON file is updated and a restart of processes (but not webserver) is initiated.
Alternatively, we could also be exporting the JSON settings to Eeprom for (potentially) easier access to the variables. Perhaps once the config is updated or a new JSON file is uploaded it would save those settings to Eeprom and not touch the JSON file. Ultimately that may come down to what is fastest and what makes the most sense. Perhaps the pin settings for example cannot be used from JSON, but could be used from Eeprom?
I have created an example of a JSON that I think could possibly work here: https://github.com/gbfans/afterlife-lightkit/blob/configuration-testing/SOFTWARE/data/config.json-example
Lots of stuff in there is of course not linked to anything in code. So I figured I would outline what I envision the pattern names are and what they would do. Feel free to chime in and provide feedback on any of these.
Cyclotron Specific Patterns
Powercell Specific Patterns
Generic Patterns
There can also be patterns for multi-color things like rainbow.
Those are just things off the top of my head. Obviously only a few of those are an initial must have.
The text was updated successfully, but these errors were encountered: