With that, I will introduce the primary focus for the first installation of this series: WLED. WLED is a lightweight web server utility to control NeoPixel (WS2812B, WS2811, SK6812) LEDs. Many people use WLED to control lights in custom-made lamps, holiday decorations, kitchen cabinet lighting, decorative house lighting, and so much more.
If you're familiar with WLED, you certainly know how powerful it is and how many ways it can be used, but one thing it's missing is a dynamic and highly-customizable scheduling system. I've seen some awesome holiday patterns posted to the WLED subreddit, which inspired me to create some complex presets using segments and such, but the one thing I kept thinking to myself is "wouldn't it be nice if my lights could just enable a preset or playlist automatically depending on the holiday?" WLED is simply a tool to control LEDs and create amazing patterns and effects, and it's a great tool for that job. Expecting it to include a complex scheduler is probably asking too much outside of the scope of the project, so I decided to figure something out.
Luckily, WLED has a pretty simple and intuitive API. To make scheduled API calls, you'll need a home server, Raspberry Pi, or something similar. I am running Ubuntu on my home server, so this guide will be focused on bash scripting, but you should be able to do something similar using Windows and Task Scheduler.
While you can do some very complex things with the API, down to controlling individual pixels, I was more focused on simply creating my presets using the GUI and then calling those presets on a dynamic schedule based on holidays, specifically US holidays for me. Holidays like Labor Day are tough because they don't fall on the same date, and it can be tough using just the date command as you'd need to figure out any dates that final Monday could fall on, but I'd also like the holiday preset to run all weekend for "big" holidays like that. Enter the only prerequisite tool you'll need for this: calendar.
The Calendar utility will create a few default calendars in the default directory /usr/share/calendar. You can even create your own calendars to use with this tool! For my purposes, however, I'm focusing on the US holiday calendar. You can query this specific calendar with the "-f" switch followed by the path to the calendar, "/usr/share/calendar/calendar.usholiday" by default. With no additional arguments, this will compare the current date as well as the next day against that calendar, and return any lines that contain a holiday. A nice additional feature of the calendar utility is if the current date is a Friday, it'll also look ahead to the following Monday for any upcoming holidays.
Now it's time to start a bash script which will run each evening, checking for any holidays. I won't go over the basics, so you'll still need to define your shell and make the script executable when finished. This guide will simply showcase some of the basic logic and functions to get you started so you can customize your own script to run exactly how you'd like!
To start, we'll need to define some variables:
To get the current month number:
month=$(date +%m)
We'll consider FRI-SUN as a weekend, so if the current day number is 5 or greater, set the variable "weekend" to "true":
if [[ $(date +%u) -ge 5 ]]; then weekend=true; fi
Now it's time for the real "meat" of the script - defining our holidays and setting a preset value. You can see all the holidays in a specific calendar by checking the contents of the calendar file:
cat /usr/share/calendar/calendar.usholiday
Take a look at the holidays you'd like to use, and copy/paste the holiday names into a file. Remember, Linux is case-sensitive so be sure to retain uppercase/lowercase letters. You probably don't need to copy the entire holiday name, but grab enough to make it unique so other holidays aren't matched accidentally. Below is a snippet from my script for Memorial Day weekend:
holiday=$(calendar -f /usr/share/calendar/calendar.usholiday | grep "Memorial Day")
holidayWeekend=$(calendar -B 3 -f /usr/share/calendar/calendar.usholiday | grep "Memorial Day")
if [ ! -z "$holiday" ] || ([ $weekend = 'true' ] && [ ! -z "$holidayWeekend" ]); then
ps=24
psBack=11
hue=lwNJxUTAxxCgwhw
fi
Let's break that down. The first line is setting the "holiday" variable. Piping in the grep command with a specific holiday name will allow us to filter any returned lines to only include the holiday we are looking for, since some days have multiple holidays and some days might have a holiday we don't want to turn lights on for.
The second line sets the "holidayWeekend" variable. Since the calendar utility only looks at the current date and ahead, the "-B 3" argument looks backwards three days for those holidays that fall on a Thursday or Friday, so the lights will turn on all weekend. For instance, Veterans' Day is on a Thursday, so the calendar utility won't return that holiday the following Friday-Sunday, so by using the "-B" switch, we can look backwards a few days to account for that.
The third line is a combined "if" statement. The first portion [ ! -z "$holiday" ] looks to see if the "holiday" variable is not empty. If there is a holiday on the current date or next day that matches the "grep" statement, this variable will be set. The second portion ([ $weekend = 'true' ] && [ ! -z "$holidayWeekend" ]) will evaluate to true if the current day is a weekend day (FRI-SUN) AND there was a holiday in the last three days. These two portions are joined with an "or" operator (||), so if the first part OR the second part is true, then the variables in the "then" block will be set as written.
And the penultimate part of the logic is setting the variables if those conditions evaluate to true. I am using "ps" as my preset variable. This number matches a preset I've already created in the WLED interface. You'll notice I am setting a few variables here, as I have lights controlled by WLED in the front of my house as well as the back, in addition to some outdoor Philips Hue lights I am also controlling. Maybe that's another blog post for another day...
Finally, close the "if" loop!
Now our holiday status has been evaluated, and if everything matches up, our "ps" variable will be set to a preset number in WLED. The final part of the script is to tell WLED to turn that preset on:
#Turn on lights if preset variable exists
if [[ $ps ]]; then
curl -s -X POST "http://WLED.IP.ADDRESS.HERE/json/state" -H "Content-Type: application/json" -d '{"on":true,"bri":255,"ps":"'"$ps"'"}'
else
curl -s -X POST "http://WLED.IP.ADDRESS.HERE/json/state" -H "Content-Type: application/json" -d '{"on":false}'
fi
Another "if" block here, this one is basically saying if the "ps" variable contains a value, then run a curl command to tell WLED to enable that preset at full brightness. Otherwise (else), if the variable does NOT contain a value, turn the lights off. That last part isn't completely necessary, but just in case the lights happen to be on for some reason, this is more of a catch-all to turn them off. You'll of course need to enter the IP address of your WLED controller where indicated above.
Now you can save the script, create a cron job to execute it every evening, and you're done! Of course, you'll want to write a second script and cron job to turn the lights off in the morning. I use a utility called heliocron so I can set my cron jobs to run at 2pm each day, but the heliocron utility ensures the scripts don't actually execute until a specified time before/after sunset/sunrise. Because sunset/sunrise times obviously change throughout the year, this ensure my lights always come on an hour before sunset and then turn off an hour after sunrise, no matter what time of year it is.
This post turned out longer than I intended, but my goal is to make sure you can create your own schedule scripts, regardless of your experience and skill level with bash/Linux. If you were able to use this to create your own WLED scheduling scripts, drop a comment below! Or, if you have any suggestions or tips to help others out, feel free to do so!
]]>It's weird, isn't it? With a little bit of time and some PLA, you can hold your own brain in the palm of your hand. Everything that makes you, you - and it's right there.
Turns out, it's not that difficult to 3D print your own brain. The hardest part is getting the MRI or CT scan, and usually you don't necessarily want a reason to have one of those. Nonetheless, if you happen to have had one in the last couple years, odds are you can get a copy of those files for your own use. Some hospitals or clinics charge a small fee for a CD with your records on it, but it's a small price to pay considering what the MRI itself costs!
I found a few guides scattered across the internet, but most were outdated, used defunct software, or left out a lot of crucial details which made this a lengthy process for me at first. I've gone ahead and made this guide to be more detailed so hopefully anybody can achieve the same results I did. Feel free to comment below with any questions, and hopefully if I can't answer them, somebody else can.
So here's what you'll need in addition to a copy of your scans. For reference, I did this on an M1 MacBook Pro, so this guide will focus on that specific operating system, but it should be similar on Linux or Windows.
The process can be summarized in four parts. First, we'll use Slicer to review the scans and pick the best one to export. Then, after exporting the scan in Slicer, we will use FreeSurfer to generate a printable 3D model out of the MRI slices. This process takes a very long time. For reference, it took about ten hours on my M1 MacBook Pro. After the model is generated, we'll clean it up and smooth it out (don't worry, not that smooth) for better printing using MeshLab. Once that's finished, the STL file will be ready for printing!
So if you're ready to proceed, just install the programs listed above and follow along!
First thing's first - you'll have to get your scans/images together and see what you've got. Most hospitals or imaging clinics will give you a CD with your scans on it. If this is the case, I would suggest copying the files to a hard drive, locally if you have the room or a portable hard drive otherwise. This will be much faster to work with than a CD.
While the most common format for MRI scans is DICOM (.dcm), some organizations might export your scans in a different format. This guide assumes your scans are in DICOM format, but they'll be converted to NifTI (.nii) format later. If your scans are already in NifTI format, compressed (.nii.gz) or uncompressed (.nii) then you're already a step ahead! My scan happened to be in DICOM format:
Once you have your image files copied to a hard drive, open Slicer. If your images were in NiFTI format, click the Add Data button, then choose either the Choose Directory to Add or Choose File(s) to Add button depending on how many files you have. Browse to your file(s) or directory, select them, and click the Open button, followed by the OK button to finish importing them.
If your files were DICOM like mine were, then you're going to click the Add DICOM Data button. Browse to the folder with your image files, and click the Import button. You should see a notification at the bottom of the window that your information was imported:
From here, you should see your name in the Patient name pane. Click your name, then click the scan in the Study pane, and then click the Load button at the bottom of the window.
Once your scans are loaded, you should see a preview on the right side of the Slicer window. If you have multiple scans, you can click the view button next to each one to see which looks best. I am not a radiologist or a doctor so I'm not really sure what the difference was between all my scans, but I chose the one which looked best and most clear from all three axis.
Once you've chosen which scan you like most, right-click the scan in the PANE and click the Export to file... option. From there, change the Export format drop-down to NifTI (.nii.gz) format and make sure the Compress checkbox is checked/ticked! Click the ... button in the Directory: field and browse to a folder on your local hard drive to export the scans to, and click Open. Make a note of the filename, and change it if you'd like. Ensure the filename has no spaces in it so there are no issues with running commands in Terminal later on.
Finally, click the Export button.
Now that you've got a compressed NifTI file, you're ready to process the images with FreeSurfer to generate a 3D model our of the scans. You should have already installed FreeSurfer using the link above. After it's installed, though, we need to export the necessary environment paths so your computer knows where the program binaries are located so they can be run without absolute references each time.
First, open Terminal. Then, confirm the location of your FreeSurfer install. For me, it was "/Applications/freesurfer/7.3.2" at the time of writing this.
Next, we need to define the location $FREESURFER_HOME as this path. Substitute the path of your FreeSurfer installation as necessary, and use the following command:
export FREESURFER_HOME=/Applications/freesurfer/7.3.2
FreeSurfer should include a script to set the rest of the environment variables and paths. Run the script like this:
source $FREESURFER_HOME/SetUpFreeSurfer.sh
From there, we're ready to start processing. Pick a name for your "subject" which will create a child directory for this project inside the FreeSurfer directory. I picked the very creative name "mybrain" but you can substitute yours in the command below. The next command will take a very, very long time to run. As previously mentioned, mine took about ten hours on an M1 MacBook Pro. If you're using a laptop, I would suggest leaving your computer plugged in and (if using a MacBook) using an app like Amphetamine to keep it from sleeping.
Let's get this model processed by running the following command, using the path to the file you exported in Slicer:
recon-all -s mybrain -all -i /path/to/your/exported/FILE.nii.gz
If you're using macOS, you can drag-and-drop the file into the terminal to have the path pasted automatically.
Now sit back, relax, and waaaiiittttt....
Once the process is finally complete, we can convert it to an STL. FreeSurfer will generate two files, one for each hemisphere of your brain, so we'll have to convert two files. Substitute your FreeSurfer path and subject name as necessary in the commands below:
cd /Applications/freesurfer/7.3.2/subjects/mybrain/surf
mris_convert rh.pial rh.pial.stl
mris_convert lh.pial lh.pial.stl
Now that we have our STL files, let's get them polished up! Open MeshLab, click Import Mesh, and browse to your subject directory where your STL files were converted above. Choose one of the STL files, use the default options if prompted, and then repeat the process to import the second STL.
You should now see a nice 3D image of your brain! Pretty cool, huh? Let's clean it up a bit for printing!
Click on Filters > Mesh Layer > Flatten Visible Layers. Click the Apply button, and check the status pane in the bottom-right corner of the window. Once you see "Merged all the layers to single mesh..." you can click the Close button.
Next, click Filters > Remeshing, Simplification, Reconstruction > Simplification: Quadratic Edge Collapse Decimation. In the Target number of faces field, I entered 200000 and was happy with the result. Click the Apply button. Again, keep an eye on the status pane until you see "Applied filter Simplification: Quadratic Edge Collapse Decimation ..." and then click the Close button.
Lastly, click Filters > Smoothing, Fairing and Deformation > Laplacian Smooth and click Apply. Once you see "Applied filter Laplacian Smooth..." in the status window, click Close.
Finally, it's time to save the finished STL for printing! Click File > Export Mesh As... and choose a folder and filename to save the finished STL. Change the file type dropdown to STL File Format and click Save.
Load up the final STL file in your favorite slicer, enable supports, and print away!
Feel free to post some pictures of your final print in the comments below if you'd like!
]]>
With the release of weatherproof enclosures for other sensors, including those from Ring, Eve, and SimpliSafe, we're really working overtime! And yet, when you place an order, it'll still be shipped out the very next day in most cases (No pun intended)!
Remember to keep PrintSpired Designs in mind for all your smart home accessory needs. When it comes to the Apple TV, HomePod mini, or any other smart home devices from Aqara, Eve, Ring, SimpliSafe, and more - check us out first!
]]>Why not make your Siri Remote easier to find without even opening your Find My app, and grab our AirTag case in glow-in-the-dark? When the lights dim during movie time, the subtle glow will ensure you're never looking around for the pesky remote.
]]>Going on sale 6/10/21...
]]>