Compare commits
79 commits
2020.05.24
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b1fd3e467 | ||
|
|
ef6f9c719f | ||
|
|
4d41fb76b5 | ||
|
|
27d5811c30 | ||
|
|
b8aa46d199 | ||
|
|
349cf13866 | ||
|
|
fe5453d469 | ||
|
|
fe1d24edfb | ||
|
|
637a92850b | ||
|
|
fb31dfd49b | ||
|
|
76ab8a58d1 | ||
|
|
7844028dd6 | ||
|
|
7eaa986423 | ||
|
|
669ee49c12 | ||
|
|
d8a5b92bca | ||
|
|
c833660c37 | ||
|
|
db38d3c8c3 | ||
|
|
dd0280a73a | ||
|
|
c833516129 | ||
|
|
5d2e6a5d22 | ||
|
|
489c41a7f2 | ||
|
|
73f4f96c47 | ||
|
|
55082d124a | ||
|
|
bc452fc92e | ||
|
|
a6c0161627 | ||
|
|
a8b9643a99 | ||
|
|
bb104ee4bb | ||
|
|
691869cdf5 | ||
|
|
fa0cb30b3f | ||
|
|
1311aa290b | ||
|
|
8d82112e28 | ||
|
|
9ce60deacd | ||
|
|
d93c18f324 | ||
|
|
6c47ebba8a | ||
|
|
e38028e7fe | ||
|
|
94a4faef7b | ||
|
|
4c10f9ca86 | ||
|
|
e0e4ccd622 | ||
|
|
3f7512b995 | ||
|
|
9345d486a5 | ||
|
|
2c859595a8 | ||
|
|
85abe78976 | ||
|
|
eecec98bb6 | ||
|
|
2c777b7082 | ||
|
|
4120078834 | ||
|
|
19f2613d8c | ||
|
|
21c70c3317 | ||
|
|
a27674b1b3 | ||
|
|
4ae05fd735 | ||
|
|
46aef2ad27 | ||
|
|
21005a0d8b | ||
|
|
402b1e6a02 | ||
|
|
03c3545c29 | ||
|
|
76b494f0f7 | ||
|
|
768b8d3a1b | ||
|
|
c293ed0b1a | ||
|
|
e9fef4deb5 | ||
|
|
33766888b3 | ||
|
|
07b890eea6 | ||
|
|
ec7e879aa7 | ||
|
|
c901ce64e8 | ||
|
|
352a78107c | ||
|
|
ee3a1882ae | ||
|
|
6ffb1731bb | ||
|
|
bc87f6d7e2 | ||
|
|
d2b6df03a5 | ||
|
|
f9a7a1031a | ||
|
|
05f04a30ee | ||
|
|
5541b73e20 | ||
|
|
a08faeeb39 | ||
|
|
4e41f311d2 | ||
|
|
f1140155f8 | ||
|
|
ba282f9392 | ||
|
|
5633018ff8 | ||
|
|
ce7d8cf501 | ||
|
|
1068f1f728 | ||
|
|
2f140b021a | ||
|
|
7f1bec89de | ||
|
|
41a6848d87 |
311 changed files with 3267 additions and 358 deletions
4
.dockerignore
Normal file
4
.dockerignore
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
.git
|
||||
**/*.hash
|
||||
**/src
|
||||
public/
|
||||
3
.gitattributes
vendored
3
.gitattributes
vendored
|
|
@ -1,2 +1,5 @@
|
|||
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
||||
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.xcf filter=lfs diff=lfs merge=lfs -text
|
||||
*.webp filter=lfs diff=lfs merge=lfs -text
|
||||
|
|
|
|||
9
.gitmodules
vendored
9
.gitmodules
vendored
|
|
@ -1,3 +1,6 @@
|
|||
[submodule "themes/KeepIt"]
|
||||
path = themes/KeepIt
|
||||
url = https://github.com/Fastbyte01/KeepIt.git
|
||||
[submodule "themes/hugo-coder"]
|
||||
path = themes/hugo-coder
|
||||
url = git@github.com:W-Floyd/hugo-coder-iconify.git
|
||||
[submodule "assets/MaterialDesign-SVG"]
|
||||
path = assets/MaterialDesign-SVG
|
||||
url = git@github.com:Templarian/MaterialDesign-SVG.git
|
||||
|
|
|
|||
0
.hugo_build.lock
Normal file
0
.hugo_build.lock
Normal file
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"Gluster"
|
||||
]
|
||||
}
|
||||
7
Dockerfile
Normal file
7
Dockerfile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
FROM hugomods/hugo:exts as hugo
|
||||
COPY . /src
|
||||
RUN hugo --minify
|
||||
|
||||
FROM nginx:alpine-slim
|
||||
COPY --from=hugo /src/public /usr/share/nginx/html
|
||||
COPY default.conf /etc/nginx/conf.d/default.conf
|
||||
147
config.toml
147
config.toml
|
|
@ -2,84 +2,89 @@ baseURL = "//notmy.space/"
|
|||
languageCode = "en"
|
||||
defaultContentLanguage = "en"
|
||||
title = "William Floyd"
|
||||
theme = "KeepIt"
|
||||
theme = "github.com/W-Floyd/hugo-coder-iconify"
|
||||
|
||||
[module]
|
||||
[[module.mounts]]
|
||||
source = 'content'
|
||||
target = 'content'
|
||||
excludeFiles = "**/media/src"
|
||||
[[module.imports]]
|
||||
path = 'github.com/hugomods/icons/vendors/mdi'
|
||||
|
||||
paginate = 20
|
||||
|
||||
pygmentsStyle = "bw"
|
||||
pygmentsCodeFences = true
|
||||
pygmentsCodeFencesGuessSyntax = true
|
||||
|
||||
paginate = 12
|
||||
enableEmoji = true
|
||||
googleAnalytics = "UA-63647911-2"
|
||||
enableRobotsTXT = true
|
||||
canonifyURLs = true
|
||||
|
||||
[sitemap]
|
||||
changefreq = "daily"
|
||||
filename = "sitemap.xml"
|
||||
priority = 0.5
|
||||
|
||||
[blackfriday]
|
||||
hrefTargetBlank = true
|
||||
nofollowLinks = true
|
||||
noreferrerLinks = true
|
||||
|
||||
[Permalinks]
|
||||
posts = "/:year/:filename/"
|
||||
|
||||
[menu]
|
||||
[[menu.main]]
|
||||
name = "Blog"
|
||||
url = "/posts/"
|
||||
weight = 1
|
||||
|
||||
[[menu.main]]
|
||||
name = "Projects"
|
||||
url = "/projects/"
|
||||
weight = 1
|
||||
|
||||
[[menu.main]]
|
||||
name = "Categories"
|
||||
url = "/categories/"
|
||||
weight = 3
|
||||
|
||||
[[menu.main]]
|
||||
name = "About"
|
||||
url = "/about"
|
||||
weight = 4
|
||||
[permalinks]
|
||||
posts = "/:year/:month/:filename/"
|
||||
|
||||
[params]
|
||||
subtitle = "This is not MySpace, it's my space"
|
||||
since = 2018
|
||||
author = "William Floyd"
|
||||
home_mode = ""
|
||||
author = "William Floyd"
|
||||
description = "William Floyd's personal website"
|
||||
gravatar = "william.png2000@gmail.com"
|
||||
dateFormat = "January 2, 2006"
|
||||
since = 2018
|
||||
colorScheme = "auto"
|
||||
|
||||
[params.gravatar]
|
||||
email = "william.png2000@gmail.com"
|
||||
# If you want to implement a Content-Security-Policy, add this section
|
||||
scriptsrc = [
|
||||
"'self'",
|
||||
"'unsafe-inline'",
|
||||
"https://cdn.jsdelivr.net/"
|
||||
]
|
||||
prefetchsrc = ["'self'"]
|
||||
|
||||
[params.social]
|
||||
GitHub = "W-Floyd"
|
||||
Linkedin = "william-floyd-906674190"
|
||||
Email = "william.png2000@gmail.com"
|
||||
Steam = "W-Floyd"
|
||||
[taxonomies]
|
||||
category = "categories"
|
||||
series = "series"
|
||||
tag = "tags"
|
||||
author = "authors"
|
||||
|
||||
[[params.social]]
|
||||
name = "Github"
|
||||
icon = "github"
|
||||
weight = 1
|
||||
url = "https://github.com/W-Floyd/"
|
||||
|
||||
[params.share]
|
||||
[[params.social]]
|
||||
name = "LinkedIn"
|
||||
icon = "linkedin"
|
||||
weight = 2
|
||||
url = "https://www.linkedin.com/in/william-floyd/"
|
||||
|
||||
[privacy]
|
||||
[privacy.disqus]
|
||||
disable = false
|
||||
[privacy.googleAnalytics]
|
||||
anonymizeIP = true
|
||||
disable = false
|
||||
respectDoNotTrack = true
|
||||
useSessionStorage = true
|
||||
[privacy.instagram]
|
||||
disable = false
|
||||
simple = true
|
||||
[privacy.twitter]
|
||||
disable = false
|
||||
enableDNT = true
|
||||
simple = true
|
||||
[privacy.vimeo]
|
||||
disable = false
|
||||
simple = true
|
||||
[privacy.youtube]
|
||||
disable = false
|
||||
privacyEnhanced = true
|
||||
[[params.social]]
|
||||
name = "Email"
|
||||
icon = "email"
|
||||
weight = 3
|
||||
url = "mailto:contact@notmy.space"
|
||||
|
||||
[[params.social]]
|
||||
name = "RSS"
|
||||
icon = "rss"
|
||||
weight = 4
|
||||
url = "https://notmy.space/posts/index.xml"
|
||||
rel = "alternate"
|
||||
type = "application/rss+xml"
|
||||
|
||||
[languages.en]
|
||||
languageName = ":uk:"
|
||||
|
||||
[[languages.en.menu.main]]
|
||||
name = "About"
|
||||
weight = 1
|
||||
url = "about/"
|
||||
|
||||
[[languages.en.menu.main]]
|
||||
name = "Resume"
|
||||
weight = 2
|
||||
url = "https://github.com/W-Floyd/misc-job/releases/download/release/William_Floyd.pdf"
|
||||
|
||||
[[languages.en.menu.main]]
|
||||
name = "Posts"
|
||||
weight = 3
|
||||
url = "posts/"
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: "About"
|
||||
date: "2018-06-19"
|
||||
date: "2023-12-15"
|
||||
---
|
||||
|
||||
I am William Floyd, this is my blog.
|
||||
|
||||
I am currently a Mechanical Engineering student at LeTourneau.
|
||||
I currently work as an Associate Project Manager at Engenious Design.
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Clickbait - The Automatic Fishing Caster"
|
||||
date: "2020-03-13"
|
||||
author: "William Floyd"
|
||||
featured_image: "/images/reduced/clickbait/20191120_224129.jpg"
|
||||
featured_image: "media/20191120_224129.webp"
|
||||
categories: [
|
||||
"Hardware",
|
||||
"Engineering",
|
||||
|
|
@ -30,15 +30,11 @@ Create a device to launch a fishing weight. It must:
|
|||
* be capable of firing 30 times over the course of 1 hour
|
||||
* (for extra credit) be wirelessly controlled
|
||||
|
||||
I was assigned as an engineering lead, and as it turned out, completed the majority of the physical project.
|
||||
This was a mutual arrangement, however - I bounced ideas off of team members as needed, and provided information needed for the report writing - they completed the report and peripheral tasks, and helped me as I found tasks that could be assigned.
|
||||
Being a small project of such singular focus, there was little in the way of division possible on tasks, not without loss of efficiency.
|
||||
|
||||
And so it was that we began brainstorming.
|
||||
|
||||
***
|
||||
|
||||

|
||||

|
||||
|
||||
The idea was fairly simple - use two smooth rods and a leadscrew to pull a carriage against springs that would then somehow fire the fishing weight.
|
||||
The choice of this mechanism was, for the most part, due to availability of parts.
|
||||
|
|
@ -46,9 +42,9 @@ I already owned the necessary rods and bearings, and springs were readily availa
|
|||
|
||||
***
|
||||
|
||||

|
||||

|
||||
|
||||
Soon, we had [some](/images/reduced/clickbait/20190919_213947.jpg) basic 3D printed parts in order - for it was 3D printing that was most accessible to us, and allowed largely unattended manufacturing while classes continued.
|
||||
Soon, we had [some](media/20190919_213947.webp) basic 3D printed parts in order - for it was 3D printing that was most accessible to us, and allowed largely unattended manufacturing while classes continued.
|
||||
Despite this early start of progress, however, the ever present tendency toward procrastination crept in.
|
||||
The usual array of excuses were made by all, and little actual work was accomplished.
|
||||
|
||||
|
|
@ -61,22 +57,22 @@ Nor was it realistic for us to budget a baitcasting reel instead of a much cheap
|
|||
|
||||
***
|
||||
|
||||

|
||||

|
||||
|
||||
Eventually, however, some progress was made - progress in something of a wrong direction, but progress nonetheless.
|
||||
As the shape of our ungainly creation began to emerge, it was clear progress needed to be made quickly.
|
||||
Once we coupled our stepper motor to the leadscrew and power tested the unit, it was also clear that change was in order.
|
||||
|
||||
So a decision was made: a cheap cordless drill would be pilfered for a battery, motor and chuck.
|
||||
A H-Bridge would need to be bought for the drill motor (I [tried to](/images/reduced/clickbait/20191025_194859.jpg) [make one](/images/reduced/clickbait/20191102_144426.jpg), but the magic smoke was released...), and a latching system needed to be made.
|
||||
A H-Bridge would need to be bought for the drill motor (I [tried to](media/20191025_194859.webp) [make one](media/20191102_144426.webp), but the magic smoke was released...), and a latching system needed to be made.
|
||||
|
||||
***
|
||||
|
||||

|
||||

|
||||
|
||||
The next week or so resulted in the beginnings of a working launch mechanism.
|
||||
With the aid of a rubber band, a latching track was put under the rods and springs, such that the motor would tension the launching carriage, then return to the front of the mechanism to allow the eventual release of the catch using a servo.
|
||||
Soon after this, the motor was [appropriately mounted to the frame](/images/reduced/clickbait/20191110_072012.jpg), with a carefully fit 3D printed socket.
|
||||
Soon after this, the motor was [appropriately mounted to the frame](media/20191110_072012.webp), with a carefully fit 3D printed socket.
|
||||
It was, it seemed, all coming together.
|
||||
|
||||
***
|
||||
|
|
@ -89,7 +85,7 @@ The end was near, or so it seemed.
|
|||
|
||||
***
|
||||
|
||||

|
||||

|
||||
|
||||
Following soon after was the reel being mounted to the device also.
|
||||
Attempts were made to use a small DC motor, but with no luck.
|
||||
|
|
@ -100,7 +96,7 @@ Remaining at this point was a means of reeling in the line, a means of depressin
|
|||
|
||||
***
|
||||
|
||||

|
||||

|
||||
|
||||
As it turned out, the very same stepper motor that had once tried to turn our leadscrew now instead would be pressed into service reeling in the line.
|
||||
Overkill, to be sure, and it's power most wastefully used, it did indeed reliably turn our reel, albeit slowly.
|
||||
|
|
@ -110,7 +106,7 @@ This saved the most time 3D printed as compared to a smaller pulley with other p
|
|||
|
||||
***
|
||||
|
||||

|
||||

|
||||
|
||||
Finally, the mechanics of the project were completed, with each component individually power tested, though not yet in tandem with one another.
|
||||
As all of this was coming about, I had also begun getting the electronics in order.
|
||||
BIN
content/posts/clickbait/media/20190919_143530.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20190919_143530.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/clickbait/media/20190919_213947.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20190919_213947.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/clickbait/media/20190919_224711.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20190919_224711.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/clickbait/media/20191003_000323.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20191003_000323.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/clickbait/media/20191004_160107.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20191004_160107.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/clickbait/media/20191010_152148.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20191010_152148.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/clickbait/media/20191025_194859.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20191025_194859.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/clickbait/media/20191102_144426.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20191102_144426.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/clickbait/media/20191110_014623.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20191110_014623.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/clickbait/media/20191110_072012.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20191110_072012.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/clickbait/media/20191115_090125.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20191115_090125.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/clickbait/media/20191118_032416.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20191118_032416.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/clickbait/media/20191120_224129.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/20191120_224129.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
0
content/posts/clickbait/media/src/.env
Normal file
0
content/posts/clickbait/media/src/.env
Normal file
BIN
content/posts/clickbait/media/src/20190919_143530.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20190919_143530.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
0fefa0a42b5ddc8f15e48e77cbadfa2fb8f25db06fc16e8e1afbc17f4e572505
|
||||
BIN
content/posts/clickbait/media/src/20190919_213947.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20190919_213947.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
524f410f6f8d7febe879205b516ff2c2de9c2b2613bb42da8a3103e196763f73
|
||||
BIN
content/posts/clickbait/media/src/20190919_224711.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20190919_224711.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
d0da1a5cca00a3d31b31769b9dc8f3c2ef5e69055d901fa8e6575ffa10d88f4a
|
||||
BIN
content/posts/clickbait/media/src/20191003_000323.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20191003_000323.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
2ad738c50c7640a8bdcdcf5d5feeb8118bbd90343596bcdf50ce00c37e631544
|
||||
BIN
content/posts/clickbait/media/src/20191004_160107.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20191004_160107.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
db26f30ae8b9406206394d6f08146d9a6c664da2f65ea30f7c0f493a2925c464
|
||||
BIN
content/posts/clickbait/media/src/20191010_152148.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20191010_152148.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
55c2322f7bba7c7d29eb3e28ce2269662f4b2016daa9b240fb236e6821b692c0
|
||||
BIN
content/posts/clickbait/media/src/20191025_194859.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20191025_194859.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
5051917955383bd82ec91d5b9082c3f1305782417ae6065e1cd1b80a220514f8
|
||||
BIN
content/posts/clickbait/media/src/20191102_144426.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20191102_144426.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
3c91e3d30fb5b38e543b11f1a21982954078f8dd5d182805f5182a59c6469041
|
||||
BIN
content/posts/clickbait/media/src/20191110_014623.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20191110_014623.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
d5e6e4baba1a9bc8858defe107721f069edf82e1c518326367a3d31f6ee8cedf
|
||||
BIN
content/posts/clickbait/media/src/20191110_072012.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20191110_072012.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
6c9c220b1d695d76e5e3a93832fe14c49b3765ac93e4d971ebe9a981d33f3ce0
|
||||
BIN
content/posts/clickbait/media/src/20191115_090125.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20191115_090125.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
24f6a28a746ea3d7213ee2ed2c40b22b756624331b24b486fd353b4abea576db
|
||||
BIN
content/posts/clickbait/media/src/20191118_032416.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20191118_032416.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
e67916e0e2ea755a40fe7859b7e46fdfc1698c24d5da7a4898b7785dbe8d1754
|
||||
BIN
content/posts/clickbait/media/src/20191120_224129.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/clickbait/media/src/20191120_224129.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
ef9c7801402a53ffc20bad84a5e5fb3587bbb2f2738d8d5df295d9e681070897
|
||||
104
content/posts/coffee/index.md
Normal file
104
content/posts/coffee/index.md
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
---
|
||||
title: "DIY 'Smart' Coffee Maker"
|
||||
date: "2020-07-05"
|
||||
author: "William Floyd"
|
||||
featured_image: "media/20200702_120123.webp"
|
||||
categories: [
|
||||
"Hardware",
|
||||
"Electronics",
|
||||
"Hacking"
|
||||
]
|
||||
tags: [
|
||||
"Hobby",
|
||||
"Home Assistant",
|
||||
"Home Automation",
|
||||
"ESPHome",
|
||||
"Coffee",
|
||||
"IOT"
|
||||
]
|
||||
---
|
||||
|
||||
I have recently (last couple months) been getting into home automation, specifically using Home Assistant.
|
||||
I also wanted to get a coffee maker that used K-Cups.
|
||||
Thus the goal was born - to get a coffee maker working with Home Assistant, such that I could automate it to fit my morning routine.
|
||||
|
||||
I first searched for new coffee makers, looking to see what the easiest ones would be to hack into and automate.
|
||||
I got so far as adding a sleek new brand name model to my Amazon cart, but thankfully reason and frugality prevailed!
|
||||
Instead, I opted to swing by the local Goodwill the next day, to see what secondhand options might be available.
|
||||
As luck would have it, I found a no-frills, single button coffee maker for the princely sum of $4, and I was on my merry way.
|
||||
|
||||

|
||||
|
||||
***
|
||||
|
||||
Later that evening, opening the black box up (thankfully I had the correct triangular screwdriver head), I found very easily hackable innards.
|
||||
|
||||

|
||||
|
||||
The control board ([front](media/20200610_205847.webp), [back](media/20200610_205841.webp)) is very simple - two buttons in parallel, an LED, and a couple resistors.
|
||||
I'm not quite sure what the logic is upstream (it un/latches on each press), but the buttons short to ground, and this is something I can work with.
|
||||
The control board has wires for ground, signal, and 5V, in that order.
|
||||
|
||||
The ordeal of hacking into the thing, and my missteps trying to do so, is rather boring really, but it produced this:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
The brains I added was a Wemos D1 Mini (thanks, Aliexpress!), with a 3.3V<->5V converter between to sense when the coffee maker is on, and also turn on a mosfet to short the button to ground.
|
||||
I initially had issues with the coffee maker turning on whenever I plugger the D1 Mini in, but a pulldown resistor solved this.
|
||||
|
||||

|
||||
|
||||
I also opted for an external USB plug - this allows me to possibly reflash this without opening the enclosure, and also meant I did not need to splice into the mains line inside, which I was reluctant to do.
|
||||
|
||||
I initially flashed and programmed the coffee maker with Tasmota, but almost immediately opted to use ESPHome instead.
|
||||
I like Tasmota and ESPHome, I was just able to get more fine control of the setup using ESPHome in this instance, especially concerning the button logic.
|
||||
|
||||
The (important) code is as follows:
|
||||
|
||||
```yaml
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
device_class: power
|
||||
internal: true
|
||||
id: power_on
|
||||
pin: D2
|
||||
|
||||
switch:
|
||||
- platform: gpio
|
||||
pin: D1
|
||||
id: relay
|
||||
restore_mode: ALWAYS_OFF
|
||||
- platform: template
|
||||
name: "Coffee Maker"
|
||||
icon: "mdi:coffee-maker"
|
||||
lambda: |-
|
||||
if (id(power_on).state) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
turn_on_action:
|
||||
- switch.turn_on: relay
|
||||
- delay: 50ms
|
||||
- switch.turn_off: relay
|
||||
turn_off_action:
|
||||
- switch.turn_on: relay
|
||||
- delay: 50ms
|
||||
- switch.turn_off: relay
|
||||
```
|
||||
|
||||
The beauty of the way in which I can detect signals and simulate a button press is that ESPHome senses when I use the physical button, and updates accordingly.
|
||||
I can use the coffee maker absolutely as normal, the 'Smart' part of it is optional.
|
||||
|
||||
***
|
||||
|
||||
The rest of my setup using this coffee maker is somewhat outside the scope of this post, but it includes using Tasker on my phone to run a 'Wakeup' automation on Home Assistant, which will - along with turning on my bed-head lamp, and switching my monitor on before putting it to sleep - check if I turned on a 'Morning Coffee' user input.
|
||||
If I remembered to prep my coffee the night before, and turned on the switch, I will wake up to a hot cup of coffee (or, the sound of a coffee-in-progress).
|
||||
I can also command Alexa and Google Assistant to do my bidding and make me a coffee.
|
||||
At least someone does what I want...
|
||||
|
||||
Truly, we are living in the future.
|
||||
BIN
content/posts/coffee/media/20200610_204856.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/20200610_204856.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/coffee/media/20200610_205351.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/20200610_205351.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/coffee/media/20200610_205841.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/20200610_205841.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/coffee/media/20200610_205847.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/20200610_205847.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/coffee/media/20200702_120123.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/20200702_120123.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/coffee/media/20200702_120302.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/20200702_120302.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/coffee/media/20200702_120309.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/20200702_120309.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/coffee/media/20200702_120328.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/20200702_120328.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/coffee/media/20200702_120334.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/20200702_120334.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
0
content/posts/coffee/media/src/.env
Normal file
0
content/posts/coffee/media/src/.env
Normal file
BIN
content/posts/coffee/media/src/20200610_204856.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/src/20200610_204856.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
1
content/posts/coffee/media/src/20200610_204856.jpg.hash
Normal file
1
content/posts/coffee/media/src/20200610_204856.jpg.hash
Normal file
|
|
@ -0,0 +1 @@
|
|||
372a99d5662d499adccdd71c8110b8d459612110babf4099bf4d5bdd7370e329
|
||||
BIN
content/posts/coffee/media/src/20200610_205351.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/src/20200610_205351.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
1
content/posts/coffee/media/src/20200610_205351.jpg.hash
Normal file
1
content/posts/coffee/media/src/20200610_205351.jpg.hash
Normal file
|
|
@ -0,0 +1 @@
|
|||
d48ea9d5b0cfd9291c110a1beb64be4d7f76f62644986b49a969bc10cce9a7ca
|
||||
BIN
content/posts/coffee/media/src/20200610_205841.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/src/20200610_205841.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
1
content/posts/coffee/media/src/20200610_205841.jpg.hash
Normal file
1
content/posts/coffee/media/src/20200610_205841.jpg.hash
Normal file
|
|
@ -0,0 +1 @@
|
|||
f53659511bd33ac8c51a8f1fae74d24551c270e8fc6870553ce4edc04add95f2
|
||||
BIN
content/posts/coffee/media/src/20200610_205847.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/src/20200610_205847.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
1
content/posts/coffee/media/src/20200610_205847.jpg.hash
Normal file
1
content/posts/coffee/media/src/20200610_205847.jpg.hash
Normal file
|
|
@ -0,0 +1 @@
|
|||
cf91c706dec4682dbddc5be255fe9e5793c61941c0284c3bb7dae9e0fb592e80
|
||||
BIN
content/posts/coffee/media/src/20200702_120123.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/src/20200702_120123.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
1
content/posts/coffee/media/src/20200702_120123.jpg.hash
Normal file
1
content/posts/coffee/media/src/20200702_120123.jpg.hash
Normal file
|
|
@ -0,0 +1 @@
|
|||
526b6f7d067f17a0b593482823cb88024a0ad1417f905e7b61f1077773acd7aa
|
||||
BIN
content/posts/coffee/media/src/20200702_120302.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/src/20200702_120302.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
1
content/posts/coffee/media/src/20200702_120302.jpg.hash
Normal file
1
content/posts/coffee/media/src/20200702_120302.jpg.hash
Normal file
|
|
@ -0,0 +1 @@
|
|||
c259c61a1fc9b3554f5e2c3ed4a0318deb92ea013b665a32534f90c4f5b6d897
|
||||
BIN
content/posts/coffee/media/src/20200702_120309.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/src/20200702_120309.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
1
content/posts/coffee/media/src/20200702_120309.jpg.hash
Normal file
1
content/posts/coffee/media/src/20200702_120309.jpg.hash
Normal file
|
|
@ -0,0 +1 @@
|
|||
14bfcaec0739089a4bbbf57c78ad3ca93286cf402c9a987fcb63a23bfffddbf5
|
||||
BIN
content/posts/coffee/media/src/20200702_120328.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/src/20200702_120328.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
1
content/posts/coffee/media/src/20200702_120328.jpg.hash
Normal file
1
content/posts/coffee/media/src/20200702_120328.jpg.hash
Normal file
|
|
@ -0,0 +1 @@
|
|||
4404536aaf5f70f51fad0e9298ecf1ead5b97e52a3557d482f89d23f7ccba1ce
|
||||
BIN
content/posts/coffee/media/src/20200702_120334.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/coffee/media/src/20200702_120334.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
1
content/posts/coffee/media/src/20200702_120334.jpg.hash
Normal file
1
content/posts/coffee/media/src/20200702_120334.jpg.hash
Normal file
|
|
@ -0,0 +1 @@
|
|||
1ee1ad4b87c3a581e97879eb627e6c478972b86a83232fbd66173390de34fb80
|
||||
102
content/posts/ghetto-nas-part-01/index.md
Normal file
102
content/posts/ghetto-nas-part-01/index.md
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
title: "Ghetto NAS Part 1"
|
||||
date: "2023-08-29"
|
||||
author: "William Floyd"
|
||||
#featured_image: "media/IMG_20220126_225541.webp"
|
||||
categories: [
|
||||
"Sys Admin",
|
||||
"Hardware",
|
||||
"Software"
|
||||
]
|
||||
tags: [
|
||||
"NAS",
|
||||
"3D Printing",
|
||||
"Gluster",
|
||||
"Homelab"
|
||||
]
|
||||
series: ["Ghetto NAS"]
|
||||
list: never
|
||||
draft: true
|
||||
---
|
||||
|
||||
This is an ongoing project to build a custom NAS on the most minimal budget possible.
|
||||
|
||||
# Use Case
|
||||
|
||||
Storing a large (30TB+) amount of infrequently accessed data that must still be immediately accessible (primarily Jellyfin, Nextcloud), with some level of safety.
|
||||
|
||||
Some details about my use case:
|
||||
* There will be no external network access except via a single local client mounting the drive and sharing via ZeroTier
|
||||
* There will be very few clients total
|
||||
* Most data is replaceable, though inconveniently so (media may be reacquired / restored from backups)
|
||||
* Neither latency nor throughput are very important
|
||||
|
||||
# Bill of Materials
|
||||
|
||||
| Quantity | Item | Per Unit Cost | Notes |
|
||||
|----------|------------------------------|---------------|-----------------------------------------------------------------------------------------------|
|
||||
| 3 | Dell Wyse 3030LT Thin Client | $11 | Ebay - Fairly common, though may run out eventually - other thin clients will no doubt appear |
|
||||
| 3 | HGST 10TB He10 510 | $80 | Amazon / Ebay - Very common, can pick these up any day |
|
||||
| 3 | ORICO 3.5in to USB enclosure | $25 | Amazon - Could use another, this is what I chose, does the job for me |
|
||||
| 5 | Ethernet Cables | $2.5 | Amazon - $12.50 / 5 pack - Or whatever you have lying around |
|
||||
| 1 | 8 Port Ethernet Switch | $13 | Amazon - Or whatever you have lying around |
|
||||
| 0.5kg | PLA | $20 | For the NAS enclosure |
|
||||
|
||||
# Rationale
|
||||
|
||||
In order of importance for my use case: Price > Redundancy > Performance
|
||||
|
||||
## Hardware
|
||||
|
||||
### Thin Client
|
||||
You simply cannot beat a whole working Linux box for $11.
|
||||
With 2GB RAM, 4GB eMMC, 1 GbE, 1 USB 3 port, and a bundled power adapter, it does the bare minimum I need.
|
||||
|
||||
### HDD
|
||||
Similarly, **used** enterprise drives deliver an amazing value.
|
||||
For less than $9/TB or just over $10/TB with the enclosure, these drives are the cheapest possible way to get storage right now.
|
||||
By using external enclosures we can also upgrade to larger drives in future, with minimal effort.
|
||||
No shucking required!
|
||||
|
||||
I buy ones that have a 5 year warranty (spoiler - it's worth having!).
|
||||
|
||||
### Networking
|
||||
1GbE is plenty enough for me, but if in future I need more speed, I can find a network switch with 10GbE uplink and scale horizontally a fair bit.
|
||||
For now, a cheap unmanaged GbE switch will do just fine.
|
||||
|
||||
### UPS
|
||||
Not 100% required, but the peace of mind in having the whole system on a UPS is worth it.
|
||||
|
||||
## Software
|
||||
|
||||
### Gluster
|
||||
|
||||
I am using Gluster to run my NAS cluster.
|
||||
This is in large part due to its very modest hardware requirements, especially memory.
|
||||
I can run my nodes with less than 50% memory utilization, and not fill my limited eMMC storage either.
|
||||
It is very easy to work with, and offers flexible redundancy configurations.
|
||||
|
||||
#### Configuration
|
||||
|
||||
I am using Gluster with a dispersed volume, using the native client on my main server to mount the volume.
|
||||
Dispersed lets me add clusters of bricks fairly easily, which suits my needs well.
|
||||
|
||||
### Netdata
|
||||
|
||||
This lets me know if/when drives get full, lets me know drive temperature from SMART data, and will email me if any hosts go offline.
|
||||
|
||||
# Experiences so far
|
||||
|
||||
I've been too busy to document the whole process, but I currently have a 2 x (2 + 1) array running (if I'd known I'd need 6 drives, I'd have done 1 x (4 + 2), but I didn't know at first).
|
||||
Capacity is 60TB raw, 40TB usable.
|
||||
|
||||
## HDD Failures
|
||||
|
||||
That 5 year warranty I mentioned?
|
||||
I've needed it twice so far - one drive died about 1 month in, and a second died 2 months in.
|
||||
To their credit, the vendor got me a return package label within one business day each time, and refunded me as soon as the return package arrived.
|
||||
For now, I continue to use these drives because the $/TB is so good, but in future I may upgrade to some larger drives in the same way to keep power costs down.
|
||||
|
||||
## Power Draw
|
||||
|
||||
6 x HDDs + 6 x Thin Clients + Network Switch + 12V Power Supply, draws about 40W at the wall under regular load (serving files).
|
||||
150
content/posts/ghetto-nas-part-02/index.md
Normal file
150
content/posts/ghetto-nas-part-02/index.md
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
---
|
||||
title: "Ghetto NAS Part 2"
|
||||
date: "2024-02-16"
|
||||
author: "William Floyd"
|
||||
#featured_image: "media/IMG_20220126_225541.webp"
|
||||
categories: [
|
||||
"Sys Admin",
|
||||
"Hardware",
|
||||
"Software"
|
||||
]
|
||||
tags: [
|
||||
"NAS",
|
||||
"3D Printing",
|
||||
"Gluster",
|
||||
"Homelab"
|
||||
]
|
||||
series: ["Ghetto NAS"]
|
||||
list: never
|
||||
draft: true
|
||||
---
|
||||
|
||||
I've been running the Gluster array from [part one](../ghetto-nas-part-01/) of this series for some months now, and am looking to improve my setup as I move to a new location and have new requirements.
|
||||
|
||||
# Existing Hardware
|
||||
|
||||
As a reminder/update, here is my existing hardware setup:
|
||||
|
||||
* Used HP Z440
|
||||
* CPU
|
||||
* Intel Xeon 1650-v4 (6 core, 12 thread, 3.6/4.0GHZ)
|
||||
* Memory
|
||||
* 128GB LRDDR4 @ 2133MT/s
|
||||
* Storage
|
||||
* 1TB NVME boot drive via PCIE adapter
|
||||
* 8TB shucked WD Easystore (bought new)
|
||||
* 14TB shucked WD Easystore (bought new)
|
||||
* GPU
|
||||
* Dell GTX 1080 (for gaming)
|
||||
* Intel Arc A380 (for transcoding)
|
||||
* 6 x Gluster Nodes
|
||||
* Dell Wyse 3030 LT Thin Client
|
||||
* CPU
|
||||
* Intel Celerton N2807 (2 core, 0.5/2.167GHz)
|
||||
* Memory
|
||||
* 2GB Memory
|
||||
* Storage
|
||||
* 4GB MMC boot drive
|
||||
* ORICO 3.5" SATA to USB 3.0 desktop adapter
|
||||
* 10TB HGST He10 (refurbished, 5 year warranty)
|
||||
* Generic 360W 12V power supply for Thin Clients and HDDs
|
||||
* Generic Gigabit ethernet switch for all thin clients and workstation
|
||||
|
||||
# Requirements
|
||||
|
||||
Given my experiences with my existing solution, my new setup must (continue) to be:
|
||||
* Able to support my existing 40TB usable space, scalable up to ~100TB
|
||||
* Easily maintainable
|
||||
* Performant
|
||||
* Mostly quiet
|
||||
* Cost effective
|
||||
* Initial cost
|
||||
* Cost over time (aiming for 5 year lifecycle)
|
||||
* Power efficient
|
||||
* Fewer Gluster nodes
|
||||
* Large disks > many disks
|
||||
* Reliable
|
||||
* ECC Memory
|
||||
* Redundant storage
|
||||
|
||||
This leaves me with the following requirements:
|
||||
* Must support a `n x (4 + 2)` disk arrangement (~67% usable space with 2 disks of redundancy, especially as I plan to use used drives)
|
||||
* Disks must be 10TB or larger
|
||||
* Disks must be cheap
|
||||
* Disks should have reasonable warranty
|
||||
|
||||
Additional observations/experience:
|
||||
* The 4GB storage on the Dell Wyse 3030 LT nodes is difficult to work in. If the storage fills, it can result in a node failing to come online after a restart
|
||||
* Network latency results in slow directory operations via Gluster
|
||||
* The workstation is already well capable of handling this many drives, it makes more sense to connect them directly to the drives as it is their only client
|
||||
|
||||
With this in mind, I want to move away from multiple storage nodes and consolidate into a more unified storage system
|
||||
|
||||
# Options
|
||||
|
||||
## NAS
|
||||
|
||||
### Prebuilt
|
||||
|
||||
Easiest option, but not my ideal as I want to learn, and know my system wholely.
|
||||
Hardware is too expensive, no expandability, so I'm not going to do it.
|
||||
Good more many people's cases though.
|
||||
|
||||
### Custom built
|
||||
|
||||
Solid option, but too expensive - I already have a workstation, I don't want another desktop holding all the drives and not doing anything useful otherwise. More of a sunk cost issue than a failure of this option, I just can't justify redundant hardware like this. Also, power draw would be increased as I'd be adding a system, not replacing.
|
||||
|
||||
If I were to do this, these are some of the options I've looked at:
|
||||
* Mini ITX motherboard
|
||||
* [All in one](https://www.aliexpress.us/item/3256806141617147.html) ([alternative](https://www.aliexpress.us/item/3256806353828287.html)) - $125-$160 depending on spec
|
||||
* 6 SATA ports, PCIE, 4x2.5GbE, NVME
|
||||
* Power efficient (<10W TDP)
|
||||
* No ECC, memory not included
|
||||
* No brand support
|
||||
* [Xeon Kit](https://www.aliexpress.us/item/3256805579918121.html) - ~$135
|
||||
* 6(?) SATA ports, PCIE, 2x2.5GbE, NVME(?)
|
||||
* Powerful, not power efficient (90W TDP)
|
||||
* ECC memory included
|
||||
* No brand support
|
||||
* Cooler not included
|
||||
* More of a replacement to my workstation
|
||||
* [3D printed case](https://modcase.com.au/products/nas)
|
||||
* NAS Case
|
||||
* [Silverstone DS308B](https://www.silverstonetek.com/en/product/info/server-nas/DS380/)
|
||||
* Too expensive ($200+)
|
||||
* [Generic 8 bay ITX enclosure](https://www.amazon.com/KCMconmey-Internal-Compatible-Backplane-Enclosure/dp/B0BXKSS8YY/)
|
||||
* Too expensive ($150)
|
||||
* No brand support
|
||||
* Leaves empty bays if expanding in 6 drive increments
|
||||
|
||||
Overall something I've strongly considered, mostly for space savings, but cost is keeping me away, as it's basically a whole new PC for each new node (unless I'm expanding somehow otherwise, which I could do via the workstation anyway).
|
||||
|
||||
## JBOD
|
||||
|
||||
Requires an external HBA/SATA expander from the workstation.
|
||||
|
||||
### Prebuilt (ex-Enterprise)
|
||||
|
||||
Strong option, moderately easy to set up.
|
||||
Concerns are:
|
||||
* Power draw
|
||||
* Noise
|
||||
* Need for rack mounting
|
||||
* More bays than I need
|
||||
|
||||
If I were to do this (and I may do some day), I would probably get an EMC KTN-STL3, a 15 bay chassis.
|
||||
|
||||
### Custom built (from scratch)
|
||||
|
||||
Too much work, don't want to *need* to design my own PCB for this.
|
||||
|
||||
### Custom built (using ex-Enterprise parts)
|
||||
|
||||
A few options,
|
||||
|
||||
https://www.supermicro.com/manuals/other/BPN-SAS3-815TQ.pdf
|
||||
|
||||
# Physical layout
|
||||
|
||||
I had begun modelling and came close to 3D printing an all in one cluster enclosure for 3 clients and 3 drives that would include a power distribution board, fan controller with temperature sensor, and panel mounted Ethernet ports.
|
||||
This was never finished, and as I look to
|
||||
184
content/posts/ghetto-nas/index.md
Normal file
184
content/posts/ghetto-nas/index.md
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
---
|
||||
title: "Ghetto NAS Part 1"
|
||||
date: "2023-08-29"
|
||||
author: "William Floyd"
|
||||
#featured_image: "media/IMG_20220126_225541.webp"
|
||||
categories: [
|
||||
"Sys Admin",
|
||||
"Hardware",
|
||||
"Software"
|
||||
]
|
||||
tags: [
|
||||
"NAS",
|
||||
"3D Printing",
|
||||
"Gluster"
|
||||
]
|
||||
series: ["Ghetto NAS"]
|
||||
---
|
||||
|
||||
This is an ongoing project to build a custom NAS on the most minimal budget possible.
|
||||
|
||||
# Use Case
|
||||
|
||||
Storing a large (30TB+) amount of infrequently accessed data that must still be immediately accessible (primarily Jellyfin), with some level of safety.
|
||||
|
||||
Some details about my use case:
|
||||
* There will be no external network access except via a single local client mounting the drive and sharing via ZeroTier
|
||||
* There will be very few clients total
|
||||
* Most data is replaceable, though inconveniently so (media may be reacquired / restored from backups)
|
||||
* Neither latency nor throughput are very important
|
||||
|
||||
# Bill of Materials
|
||||
|
||||
| Quantity | Item | Per Unit Cost | Notes |
|
||||
|----------|------------------------------|---------------|-----------------------------------------------------------------------------------------------|
|
||||
| 3 | Dell Wyse 3030LT Thin Client | $11 | Ebay - Fairly common, though may run out eventually - other thin clients will no doubt appear |
|
||||
| 3 | HGST 10TB He10 510 | $80 | Amazon / Ebay - Very common, can pick these up any day |
|
||||
| 3 | ORICO 3.5in to USB enclosure | $25 | Amazon - Could use another, this is what I chose, does the job for me |
|
||||
| 5 | Ethernet Cables | $2.5 | Amazon - $12.50 / 5 pack - Or whatever you have lying around |
|
||||
| 1 | 8 Port Ethernet Switch | $13 | Amazon - Or whatever you have lying around |
|
||||
| 0.5kg | PLA | $20 | For the NAS enclosure |
|
||||
|
||||
# Rationale
|
||||
|
||||
In order of importance for my use case: Price > Redundancy > Performance
|
||||
|
||||
## Hardware
|
||||
|
||||
### Thin Client
|
||||
You simply cannot beat a whole working Linux box for $11.
|
||||
With 2GB RAM, 4GB eMMC, 1 GbE, 1 USB 3 port, and a bundled power adapter, it does the bare minimum I need.
|
||||
|
||||
### HDD
|
||||
Similarly, **used** enterprise drives deliver an amazing value.
|
||||
For less than $9/TB or just over $10/TB with the enclosure, these drives are the cheapest possible way to get storage right now.
|
||||
By using external enclosures we can also upgrade to larger drives in future, with minimal effort.
|
||||
No shucking required!
|
||||
|
||||
I buy ones that have a 5 year warranty (spoiler - it's worth having!).
|
||||
|
||||
### Networking
|
||||
1GbE is plenty enough for me, but if in future I need more speed, I can find a network switch with 10GbE uplink and scale horizontally a fair bit.
|
||||
For now, a cheap unmanaged GbE switch will do just fine.
|
||||
|
||||
### UPS
|
||||
Not 100% required, but the peace of mind in having the whole system on a UPS is worth it.
|
||||
|
||||
## Software
|
||||
|
||||
### Gluster
|
||||
|
||||
I am using Gluster to run my NAS cluster.
|
||||
This is in large part due to its very modest hardware requirements, especially memory.
|
||||
I can run my nodes with less than 50% memory utilization, and not fill my limited eMMC storage either.
|
||||
It is very easy to work with, and offers flexible redundancy configurations.
|
||||
|
||||
#### Configuration
|
||||
|
||||
I am using Gluster with a dispersed volume, using the native client on my main server to mount the volume.
|
||||
Dispersed lets me add clusters of bricks fairly easily, which suits my needs well.
|
||||
|
||||
### Netdata
|
||||
|
||||
This lets me know if/when drives get full, lets me know drive temperature from SMART data, and will email me if any hosts go offline.
|
||||
|
||||
# Experiences so far
|
||||
|
||||
I've been too busy to document the whole process, but I currently have a 2 x (2 + 1) array running (if I'd known I'd need 6 drives, I'd have done 1 x (4 + 2), but I didn't know at first).
|
||||
Capacity is 60TB raw, 40TB usable.
|
||||
|
||||
## HDD Failures
|
||||
|
||||
That 5 year warranty I mentioned?
|
||||
I've needed it twice so far - one drive died about 1 month in, and a second died 2 months in.
|
||||
To their credit, the vendor got me a return package label within one business day each time, and refunded me as soon as the return package arrived.
|
||||
For now, I continue to use these drives because the $/TB is so good, but in future I may upgrade to some larger drives in the same way to keep power costs down.
|
||||
|
||||
## Power Draw
|
||||
|
||||
6 x HDDs + 6 x Thin Clients + Network Switch + 12V Power Supply, draws about 40W at the wall under regular load (serving files).
|
||||
|
||||
# Topology
|
||||
|
||||
{{<mermaid>}}
|
||||
%%{
|
||||
init: {
|
||||
'theme': 'base',
|
||||
'themeVariables': {
|
||||
'background': '#00000000',
|
||||
'primaryColor': '#00000000',
|
||||
'primaryTextColor': '#888888',
|
||||
'secondaryColor': '#00000000',
|
||||
'primaryBorderColor': '#888888',
|
||||
'secondaryBorderColor': '#888888',
|
||||
'secondaryTextColor': '#888888',
|
||||
'tertiaryColor': '#00000000',
|
||||
'tertiaryBorderColor': '#888888',
|
||||
'tertiaryTextColor': '#888888',
|
||||
'noteBkgColor': '#00000000',
|
||||
'noteTextColor': '#888888',
|
||||
'noteBorderColor': '#888888',
|
||||
'lineColor': '#888888',
|
||||
'textColor': '#888888',
|
||||
'mainBkg': '#00000000',
|
||||
'errorBkgColor': '#00000000',
|
||||
'errorTextColor': '#888888'
|
||||
}
|
||||
}
|
||||
}%%
|
||||
graph TB
|
||||
|
||||
subgraph internet["Internet"]
|
||||
me_away["Me when away from home"] & Friends & Family & Fiancé --- caddy
|
||||
subgraph vps["Cloud VPS"]
|
||||
caddy --- vps_zerotier["Zerotier"] & rss
|
||||
subgraph vps_docker["Docker"]
|
||||
caddy["Caddy"]
|
||||
rss["FreshRSS"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
vps_zerotier ---- zerotier
|
||||
|
||||
subgraph home["Home Network"]
|
||||
|
||||
z440 ---- me_home["Me at home"]
|
||||
|
||||
subgraph z440["Server (HP Z440)"]
|
||||
|
||||
zerotier["Zerotier"] --- jellyfin & arr & ha_zerotier
|
||||
|
||||
subgraph docker[Docker]
|
||||
jellyfin["Jellyfin"]
|
||||
arr["*arr Applications"]
|
||||
end
|
||||
|
||||
subgraph vms["VMs"]
|
||||
subgraph ha["Home Assistant"]
|
||||
ha_zerotier["Zerotier"]
|
||||
end
|
||||
end
|
||||
|
||||
jellyfin & arr --- gluster["Gluster mount"]
|
||||
|
||||
jellyfin & arr --- disk_internal["Internal Disks"]
|
||||
|
||||
end
|
||||
|
||||
ha ---- smart_home_devices["Smart Home Devices"]
|
||||
|
||||
gluster --- switch["GbE Network Switch"] --- client1 & client2 & client3 & client4 & client5 & client6
|
||||
|
||||
client1[1.wyse] --"USB"--- disk1[Disk 1]
|
||||
client2[2.wyse] --"USB"--- disk2[Disk 2]
|
||||
client3[3.wyse] --"USB"--- disk3[Disk 3]
|
||||
client4[4.wyse] --"USB"--- disk4[Disk 4]
|
||||
client5[5.wyse] --"USB"--- disk5[Disk 5]
|
||||
client6[6.wyse] --"USB"--- disk6[Disk 6]
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
{{</mermaid>}}
|
||||
320
content/posts/home-automation-at-school/index.md
Normal file
320
content/posts/home-automation-at-school/index.md
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
---
|
||||
title: "Home Automation at School"
|
||||
date: "2021-04-21"
|
||||
author: "William Floyd"
|
||||
featured_image: "media/20200813_023018.webp"
|
||||
categories: [
|
||||
"Software"
|
||||
]
|
||||
tags: [
|
||||
"School",
|
||||
"Home Assistant",
|
||||
"Home Automation",
|
||||
"ESPHome",
|
||||
"IOT"
|
||||
]
|
||||
---
|
||||
|
||||
I love home automation - I've spent far longer writing automation routines and hacking together my own devices and programs than I have ever saved by doing so, and that's perfectly fine.
|
||||
One unique aspect of my setup, however, is that I cannot control the network I must use - in my Uni dorm, I am not allowed to run my own router, and so all IoT devices must connect to the school wireless network.
|
||||
There abound dozens of Google Home devices, Chromecasts, and so on, all accessible on the same network - but not from the wired connection that my server/desktop uses.
|
||||
|
||||
Here then is my solution: MQTT everything I can.
|
||||
From my lights, so light sensor, to coffee maker to desktop software, I bounce it through a MQTT server hosted on a VPS.
|
||||
I use Home Assistant, so automatic discovery is easy on most things, especially ESPHome.
|
||||
In fact, I disabled direct Home Assistant connectivity entirely on these devices, which works well enough for me to live with.
|
||||
|
||||
# But how to flash?
|
||||
|
||||
Given that my Home Assistant instance isn't even on the same network as the IoT devices, how do I update the firmware?
|
||||
Using my laptop, I can connect to the wireless network that they reside on, and using IP address sensors reported by these devices, flash them directly without needing local discovery.
|
||||
In fact, I can easily automate this for myself using a couple scripts and a minimal number of hard-coded values:
|
||||
|
||||
`hassio.sh`
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
export HASS_SERVER=https://<server_url>:443
|
||||
export HASS_TOKEN='<HA_Token>'
|
||||
|
||||
hass-cli ${@}
|
||||
|
||||
exit
|
||||
|
||||
```
|
||||
|
||||
`lamps.sh`
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
declare -A aa
|
||||
|
||||
aa["gosund_lb1_1.yaml"]="sensor.desk_lamp_ip_address"
|
||||
aa["gosund_lb1_2.yaml"]="sensor.bed_lamp_ip_address"
|
||||
aa["gosund_lb1_3.yaml"]="sensor.floor_lamp_girlfriend_ip_address"
|
||||
aa["gosund_lb1_4.yaml"]="sensor.desk_lamp_girlfriend_ip_address"
|
||||
aa["gosund_lb1_5.yaml"]="sensor.floor_lamp_ip_address"
|
||||
|
||||
__flash() {
|
||||
|
||||
__config="${1}"
|
||||
__entity_name="${aa[${__config}]}"
|
||||
echo "Getting ${__config} IP..."
|
||||
|
||||
__ip="$(
|
||||
./hassio.sh -o yaml state get \
|
||||
"${__entity_name}" |
|
||||
grep -E '^ *state' | sed -e 's/.* //'
|
||||
)"
|
||||
|
||||
echo "IP: ${__ip}"
|
||||
|
||||
if [ "${__ip}" == 'unavailable' ]; then
|
||||
echo 'Ignoring...'
|
||||
else
|
||||
echo "Flashing..."
|
||||
./esphome.sh "${__config}" run --upload-port="${__ip}"
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
}
|
||||
|
||||
if [ "${#}" -gt 0 ]; then
|
||||
until [ "${#}" == 0 ]; do
|
||||
__flash "${1}"
|
||||
shift
|
||||
done
|
||||
else
|
||||
for __config in ${!aa[@]}; do
|
||||
__flash "${__config}"
|
||||
done
|
||||
fi
|
||||
|
||||
exit
|
||||
```
|
||||
|
||||
this allows me to mostly painlessly flash my devices, though truth be told there is little need.
|
||||
|
||||
# Custom software
|
||||
|
||||
I developed for myself a tool in Golang to help tie more of my devices together.
|
||||
It is rather uncreatively/cryptically named `ha-mqtt-iot` - that is, "Home Assistant MQTT Internet of Things".
|
||||
I may rename this some day, but why bother.
|
||||
It is similar to IOTLink (which is Windows only), and HASS Workstation Service - they are great projects, but this one is mine, even if it is poorly written.
|
||||
|
||||
The gist of the software is that most (all?) device types supported by Home Assistant may be implemented using a selection of user defined commands.
|
||||
The most prominent examples in my case are in order to enable/disable dark mode on my desktop.
|
||||
I automate this according to ambient light in my room, to better match the aesthetic I want.
|
||||
Additionally, I can use it to turn my desktop monitor off, without resorting to using a relay outlet, and even change the color temperature of my system.
|
||||
The script I use for this looks like the following:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
__monitor_i2c='dev:/dev/i2c-3'
|
||||
__monitor_dpms='0xd6'
|
||||
__monitor_brightness='0x10'
|
||||
__monitor_standby='4'
|
||||
__monitor_off='5'
|
||||
__monitor_on='1'
|
||||
|
||||
__unknown() {
|
||||
echo "Unknown ${1}"
|
||||
}
|
||||
|
||||
f2i() {
|
||||
awk 'BEGIN{for (i=1; i<ARGC;i++)
|
||||
printf "%.0f\n", ARGV[i]}' "$@"
|
||||
}
|
||||
|
||||
com="${1}"
|
||||
arg="${2}"
|
||||
|
||||
case "${com}" in
|
||||
"command")
|
||||
case "${arg}" in
|
||||
"ON")
|
||||
xset dpms force on
|
||||
;;
|
||||
"OFF")
|
||||
(
|
||||
#xset dpms force off
|
||||
#sleep 0.5s
|
||||
#ddccontrol -r "${__monitor_dpms}" -w "${__monitor_standby}" "${__monitor_i2c}" -f
|
||||
#sleep 2s
|
||||
ddccontrol -r "${__monitor_dpms}" -w "${__monitor_off}" "${__monitor_i2c}" -f
|
||||
) &
|
||||
;;
|
||||
*)
|
||||
__unknown "${arg}"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"command-state")
|
||||
echo -n "$(xset q | grep 'Monitor is' | sed -e 's/.* //' | tr '[:lower:]' '[:upper:]')"
|
||||
;;
|
||||
"color-temp")
|
||||
v="$(f2i "$(bc -l <<<"1000000/${arg}")")"
|
||||
./scripts/run-in-user-session.sh gsettings set org.gnome.settings-daemon.plugins.color night-light-temperature "${v}"
|
||||
;;
|
||||
"color-temp-state")
|
||||
v="$(./scripts/run-in-user-session.sh gsettings get org.gnome.settings-daemon.plugins.color night-light-temperature)"
|
||||
echo -n "$(f2i "$(bc -l <<<"1000000/${v/* /}")")"
|
||||
;;
|
||||
"brightness")
|
||||
ddccontrol -r "${__monitor_brightness}" "${__monitor_i2c}" -w "${arg}"
|
||||
;;
|
||||
"brightness-state")
|
||||
echo -n "$(ddccontrol 2>/dev/null -r "${__monitor_brightness}" "${__monitor_i2c}" | tail -n 1 | grep -o '/[0-9]*/100' | sed -e 's|^/||' -e 's|/.*||')"
|
||||
;;
|
||||
|
||||
*)
|
||||
__unknown "root command ${com}"
|
||||
;;
|
||||
esac
|
||||
|
||||
exit
|
||||
```
|
||||
|
||||
Note that the display doesn't respond to being turned back on, so this is somewhat incomplete, but it's good enough for my needs.
|
||||
The corresponding portion of the config for `ha-mqtt-iot` looks like the following:
|
||||
|
||||
```json
|
||||
"lights": [
|
||||
{
|
||||
"info": {
|
||||
"name": "Desktop Monitor",
|
||||
"id": "monitor"
|
||||
},
|
||||
"command": [
|
||||
"./scripts/monitor.sh",
|
||||
"command"
|
||||
],
|
||||
"command_state": [
|
||||
"./scripts/monitor.sh",
|
||||
"command-state"
|
||||
],
|
||||
"command_color_temp": [
|
||||
"./scripts/monitor.sh",
|
||||
"color-temp"
|
||||
],
|
||||
"command_color_temp_state": [
|
||||
"./scripts/monitor.sh",
|
||||
"color-temp-state"
|
||||
],
|
||||
"command_brightness": [
|
||||
"./scripts/monitor.sh",
|
||||
"brightness"
|
||||
],
|
||||
"command_brightness_state": [
|
||||
"./scripts/monitor.sh",
|
||||
"brightness-state"
|
||||
],
|
||||
"brightness_scale": 100,
|
||||
"update_interval": 5
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Pretty simple.
|
||||
This makes custom system sensors trivial.
|
||||
For example, to show my system IP, I use the following:
|
||||
|
||||
```json
|
||||
"sensors": [
|
||||
{
|
||||
"info": {
|
||||
"name": "IP Address Desktop Solus",
|
||||
"id": "ip-address-desktop-solus",
|
||||
"icon": "mdi:ip-network"
|
||||
},
|
||||
"command_state": [
|
||||
"/bin/bash",
|
||||
"-c",
|
||||
"ip -j address show eno1 | jq -r '.[0].addr_info[0].local'"
|
||||
],
|
||||
"update_interval": 10
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Some common use cases are built in as well.
|
||||
Currently, this includes laptop displays (as lights) and batteries (as sensors), as well as Crypto prices (though the CoinGecko Golang library).
|
||||
These are really easy to call.
|
||||
An exhaustive example is quite short:
|
||||
|
||||
```json
|
||||
"builtin": {
|
||||
"prefix": "Name Prefix ",
|
||||
"backlight": {
|
||||
"enable": true,
|
||||
"temperature": false,
|
||||
"range": {
|
||||
"minimum": 0.025,
|
||||
"maximum": 0.95
|
||||
}
|
||||
},
|
||||
"battery": {
|
||||
"enable": true
|
||||
},
|
||||
"crypto": [
|
||||
{
|
||||
"coin_name": "dogecoin",
|
||||
"currency_name": "usd",
|
||||
"update_interval": 1,
|
||||
"icon": "mdi:currency-usd"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This lets me tailor my setup to each machine I'm using, while still enjoying the benefits of Home Assistant MQTT Discovery.
|
||||
The primary limitation at present is the inability to signal to `ha-mqtt-iot` from another process - it can only poll for changes.
|
||||
This will be addressed one day, when it is important for my own needs.
|
||||
|
||||
# How to host?
|
||||
|
||||
But the question is now, how do I access my HomeAssistant instance if it's also hosted at school?
|
||||
I most certainly don't have a public IP, so in comes AutoSSH.
|
||||
I'm not sure which is the best one at this stage, but refer to [this](https://github.com/psallandre/hassio-addons-autossh) repo and check the various forks of the parent project.
|
||||
|
||||
I have configured on my VPS a docker image that accepts reverse SSH tunnelling, authorized only to the key of the HA addon.
|
||||
From my `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
homeassistant:
|
||||
image: "docker.io/panubo/sshd"
|
||||
container_name: homeassistant
|
||||
environment:
|
||||
- TCP_FORWARDING=true
|
||||
- GATEWAY_PORTS=true
|
||||
- SSH_ENABLE_ROOT=true
|
||||
- DISABLE_SFTP=true
|
||||
volumes:
|
||||
- "./hassio/authorized_keys:/root/.ssh/authorized_keys:ro"
|
||||
- ./docker-config/hassio/data/:/data
|
||||
- ./docker-config/hassio/keys/:/etc/ssh/keys
|
||||
ports:
|
||||
- "<MY_PORT>:22"
|
||||
restart: unless-stopped
|
||||
hostname: "homeassistant"
|
||||
```
|
||||
|
||||
This is then reverse proxied to using Caddy, to expose the website on a subdomain of a website.
|
||||
From my `Caddyfile`:
|
||||
|
||||
```dockerfile
|
||||
<MY_SUBDOMAIN>.{$MY_DOMAIN} {
|
||||
reverse_proxy homeassistant:8123
|
||||
encode gzip
|
||||
}
|
||||
```
|
||||
|
||||
Pretty simple, but not without some hiccups now and again - I occasionally have to restart the sshd docker on my VPS if something goes wrong with HomeAssistant.
|
||||
|
||||
# Bonus: Android tie in
|
||||
|
||||
I use Sleep As Android to track my sleeping patterns, and as my alarm clock.
|
||||
Using Tasker, I can run an action when I begin sleep tracking, which (using a HomeAssistant plugin for Tasker) can call a script on my HomeAssistant instance to turn off my lights (only if I'm home, of course).
|
||||
Similarly, it turns on my bedhead light when my alarm goes off in the morning, and could optionally make me coffee...
|
||||
BIN
content/posts/home-automation-at-school/media/20200813_023018.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/home-automation-at-school/media/20200813_023018.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
0
content/posts/home-automation-at-school/media/src/.env
Normal file
0
content/posts/home-automation-at-school/media/src/.env
Normal file
BIN
content/posts/home-automation-at-school/media/src/20200813_023018.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/home-automation-at-school/media/src/20200813_023018.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
70c3922ade2b73a7a949d1015e738013903342a5860c7dae3525ff8b436e424c
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "midiMixer - A simple Arduino powered MIDI potentiometer bank"
|
||||
date: "2020-05-06"
|
||||
author: "William Floyd"
|
||||
featured_image: "/images/reduced/midiMixer/v1/20200506_152408.jpg"
|
||||
featured_image: "media/v1/20200506_152408.webp"
|
||||
categories: [
|
||||
"Hardware",
|
||||
"PCB",
|
||||
|
|
@ -27,12 +27,12 @@ But in the back of my head I still wanted to build some hardware to help with th
|
|||
|
||||
***
|
||||
|
||||

|
||||

|
||||
|
||||
This eventually came about in the summer of 2019, when I finally hand-wired a simple 8 knob control surface.
|
||||
Truth be told, I actually built two.
|
||||
The [first one](/images/reduced/midiMixer/handwired/20190811_005806.jpg) had some issues (I wonder why...?), and would sporadically jitter values.
|
||||
The [second one](/images/reduced/midiMixer/handwired/20190812_181606.jpg) worked correctly, having been [wired](/images/reduced/midiMixer/handwired/20190811_195900.jpg) much more [carefully](/images/reduced/midiMixer/handwired/20190811_200447.jpg).
|
||||
The [first one](media/handwired/20190811_005806.webp) had some issues (I wonder why...?), and would sporadically jitter values.
|
||||
The [second one](media/handwired/20190812_181606.webp) worked correctly, having been [wired](media/handwired/20190811_195900.webp) much more [carefully](media/handwired/20190811_200447.webp).
|
||||
|
||||
Still, it was lacking professionalism, polish, and most importantly, robustness.
|
||||
The sandwich of 22AWG wire, cardstock and PCB was less than sturdy, so I promptly packed it away and never used it.
|
||||
|
|
@ -41,28 +41,28 @@ This would come to change, however, in April of 2020.
|
|||
|
||||
***
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
Fast forward close to a year, and here we are - toilet paper is the currency of the quickly collapsing Covid19 crazed world, and I'm back with my grandparents for the remainder of my semester (which, as of writing, is all but concluded).
|
||||
Finding my lack of a social life leaving me with a little bit more free time, and being home yielding a *lot* more distractions, I learned the basics of KiCAD from YouTube, and set out to design a simple PCB.
|
||||
My old MIDI controller project came to mind, so I set myself to it, and within a few days had my first Gerber files sent off to JLCPCB.
|
||||
In reality, I should have waited a bit and done a couple more design iterations before committing, but I guess $7 is the price of impatience.
|
||||
|
||||

|
||||

|
||||
|
||||
So it was that my crisp PCBs showed up 3 weeks later - I had one assembled within the hour, and my old code dusted off and flashed within two hours.
|
||||
It's really as simple as it gets - a [Pro Micro](/images/reduced/midiMixer/v1/20200506_152023.jpg) hooked up to a [4051 analogue multiplexer](/images/reduced/midiMixer/v1/20200506_152016.jpg), in turn hooked up to 8 potentiometers.
|
||||
It's really as simple as it gets - a [Pro Micro](media/v1/20200506_152023.webp) hooked up to a [4051 analogue multiplexer](media/v1/20200506_152016.webp), in turn hooked up to 8 potentiometers.
|
||||
|
||||
The potentiometers I had on hand ended up being a bit different than the footprints I had used, so I ended up having to clip the mounting tabs off of them.
|
||||
This, as one might imagine, made them extraordinarily flimsy, so I designed and printed a couple clamps to [align](/images/reduced/midiMixer/v1/20200506_151947.jpg) and [hold solid](/images/reduced/midiMixer/v1/20200506_152003.jpg) the potentiometers.
|
||||
This, as one might imagine, made them extraordinarily flimsy, so I designed and printed a couple clamps to [align](media/v1/20200506_151947.webp) and [hold solid](media/v1/20200506_152003.webp) the potentiometers.
|
||||
These also have the added benefit of keeping the soldered pins off of whatever surface the mixer is on.
|
||||
Should the correct potentiometers be used, these would not be needed, though some feet or a case for the PCB would still be best.
|
||||
|
||||
***
|
||||
|
||||

|
||||

|
||||
|
||||
This being my first PCB design, I am quite happy it worked out so well - I am studying for Mechanical Engineering, not Electrical...
|
||||
However, I see room for improvement.
|
||||
|
|
@ -71,4 +71,4 @@ The knobs barely clear the Arduino, and the Arduino is mounted far higher off th
|
|||
I see myself making a v2 in due course - perhaps next time I will try JLCPCB's SMT assembly?
|
||||
I imagine adding indicator LEDs, improving the layout, and adding a button to switch between banks would make this much more useful.
|
||||
|
||||

|
||||

|
||||
BIN
content/posts/midiMixerV1/media/handwired/20190811_004928.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/midiMixerV1/media/handwired/20190811_004928.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/midiMixerV1/media/handwired/20190811_005806.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/midiMixerV1/media/handwired/20190811_005806.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/midiMixerV1/media/handwired/20190811_195900.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/midiMixerV1/media/handwired/20190811_195900.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/midiMixerV1/media/handwired/20190811_200447.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/midiMixerV1/media/handwired/20190811_200447.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/midiMixerV1/media/handwired/20190812_175132.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/midiMixerV1/media/handwired/20190812_175132.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
content/posts/midiMixerV1/media/handwired/20190812_181606.webp
(Stored with Git LFS)
Normal file
BIN
content/posts/midiMixerV1/media/handwired/20190812_181606.webp
(Stored with Git LFS)
Normal file
Binary file not shown.
0
content/posts/midiMixerV1/media/src/.env
Normal file
0
content/posts/midiMixerV1/media/src/.env
Normal file
BIN
content/posts/midiMixerV1/media/src/handwired/20190811_004928.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/midiMixerV1/media/src/handwired/20190811_004928.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
80bebd4e51d1aaabde9777b00e87e415e73f4b5fe6a0acbf5f675fad2bab3ea9
|
||||
BIN
content/posts/midiMixerV1/media/src/handwired/20190811_005806.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/midiMixerV1/media/src/handwired/20190811_005806.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1 @@
|
|||
4e34713687f375c61df8d71d6e49adfb643f3f5df0ba8a919273e8b66b48e6f8
|
||||
BIN
content/posts/midiMixerV1/media/src/handwired/20190811_195900.jpg
(Stored with Git LFS)
Normal file
BIN
content/posts/midiMixerV1/media/src/handwired/20190811_195900.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue