Compare commits

...

79 commits

Author SHA1 Message Date
William Floyd
1b1fd3e467
all: Add content, update for theme updates. 2024-12-01 23:55:57 -06:00
William Floyd
ef6f9c719f
nas: Add diagram 2024-04-30 11:34:13 -05:00
William Floyd
4d41fb76b5
all: Move to custom theme that uses lightweight SVG icons. 2024-02-16 14:35:02 -06:00
William Floyd
27d5811c30
about: Remove current position. 2024-01-28 18:19:00 -06:00
William Floyd
b8aa46d199
theme: Update. 2024-01-28 18:18:53 -06:00
William Floyd
349cf13866
theme: Update 2024-01-12 12:33:40 -06:00
William Floyd
fe5453d469
content: Clickbait - remove fluff. 2024-01-12 12:33:21 -06:00
William Floyd
fe1d24edfb
ghetto-nas: Add part 1 (kinda draft. 2023-08-29 23:02:02 -05:00
William Floyd
637a92850b
theme: Update. 2023-08-29 23:01:33 -05:00
William Floyd
fb31dfd49b
pen-plotter: Fix images. 2023-07-17 14:11:37 -05:00
William Floyd
76ab8a58d1
nginx: Fix 404 page. 2023-07-17 14:10:41 -05:00
William Floyd
7844028dd6
nginx: Add config for 404 page. 2023-07-14 16:49:12 -05:00
William Floyd
7eaa986423
yogurt: Add draft for pt 3 2023-07-14 15:34:50 -05:00
William Floyd
669ee49c12
images: Use sha256 instead of md5. 2023-07-14 15:34:11 -05:00
William Floyd
d8a5b92bca
script: Isolate steps to allow PNG file processing, make file size depend on source format. 2023-07-14 15:10:56 -05:00
William Floyd
c833660c37
image: Re-add PNG->WEBP files. 2023-07-14 15:10:34 -05:00
William Floyd
db38d3c8c3
config: Cleanup. 2023-07-14 14:48:10 -05:00
William Floyd
dd0280a73a
yogurt: Use series tag instead of manually. 2023-07-14 13:49:17 -05:00
William Floyd
c833516129
rice: Update svg. 2023-07-14 13:48:56 -05:00
William Floyd
5d2e6a5d22
about: Update job about. 2023-07-14 13:48:37 -05:00
William Floyd
489c41a7f2
config: Update email. 2023-07-14 13:48:10 -05:00
William Floyd
73f4f96c47
mathjax: Update. 2023-07-14 13:47:47 -05:00
William Floyd
55082d124a
content: Update all images, many reduced in size. 2023-07-14 13:47:28 -05:00
William Floyd
bc452fc92e
docker: Make slim. 2023-07-14 13:42:51 -05:00
William Floyd
a6c0161627
scripts: Check deps, cleanup, max image size. 2023-07-14 13:41:35 -05:00
William Floyd
a8b9643a99
static: move images to work with theme. 2022-06-20 23:46:45 -04:00
William Floyd
bb104ee4bb
config: Move to new (maintained) theme. 2022-06-20 20:58:07 -04:00
William Floyd
691869cdf5
all: Consolidate projects and posts, use built in syntax highlighting, use permalinks. 2022-06-19 17:05:02 -04:00
William Floyd
fa0cb30b3f
xcf: Resave with better compression settings. 2022-03-17 10:57:59 -05:00
William Floyd
1311aa290b
content: Remove reference to non-existant src directories and update file hashes given script changes. 2022-03-17 10:48:11 -05:00
William Floyd
8d82112e28
pen-plotter: Move to 4MP image. 2022-03-17 10:47:43 -05:00
William Floyd
9ce60deacd
config: Ignore source files to save space. 2022-03-17 10:47:16 -05:00
William Floyd
d93c18f324
image-build: Remove many image settings, use WEBP settings, correctly listen for script settings. 2022-03-17 10:46:18 -05:00
William Floyd
6c47ebba8a
yogurt: Clean up image. 2022-03-17 09:53:19 -05:00
William Floyd
e38028e7fe
yogurt: Use longer time frame to show stability. 2022-03-17 09:52:17 -05:00
William Floyd
94a4faef7b
config: Disable classes in highlighting to correct behaviour. 2022-03-17 03:15:17 -05:00
William Floyd
4c10f9ca86
layouts: Get custom layouts in sync with upstream./ 2022-03-17 03:15:00 -05:00
William Floyd
e0e4ccd622
theme: Update. 2022-03-17 02:38:42 -05:00
William Floyd
3f7512b995
docker: ignore public. 2022-03-17 02:38:35 -05:00
William Floyd
9345d486a5
docker: Add pusher and dockerignore. 2022-03-17 02:33:50 -05:00
William Floyd
2c859595a8
yogurt: Add part 2. 2022-03-17 02:18:25 -05:00
William Floyd
85abe78976
content: Move all images to WEBP due to size reduction and quality improvement. 2022-03-17 02:17:58 -05:00
William Floyd
eecec98bb6
gitattributes: LFS WEBP 2022-03-17 02:16:51 -05:00
William Floyd
2c777b7082
yogurt: Add preliminary part 2. 2022-03-16 23:31:03 -05:00
William Floyd
4120078834
yogurt: Add part 1 block post (force push to use lfs to xcf). 2022-03-16 23:29:58 -05:00
William Floyd
19f2613d8c
gitattributes: LFS XCF files. 2022-03-16 23:29:43 -05:00
William Floyd
21c70c3317
pen-plotter. 2021-12-26 01:13:14 -05:00
William Floyd
a27674b1b3
ha-school: Fix indentation. 2021-12-26 00:26:52 -05:00
William Floyd
4ae05fd735
code: move one back to yaml 2021-04-22 01:31:47 -05:00
William Floyd
46aef2ad27
code: Add tags to correct color on website. 2021-04-22 01:27:05 -05:00
William Floyd
21005a0d8b
theme: Update 2021-04-22 01:18:23 -05:00
William Floyd
402b1e6a02
home-automation: Add at school post. 2021-04-22 01:18:12 -05:00
William Floyd
03c3545c29
Dockerfile: Use latest hugo 2021-03-28 19:24:30 -05:00
William Floyd
76b494f0f7
nissan: Fix typos. 2021-03-28 19:20:36 -05:00
William Floyd
768b8d3a1b
config: Allow robots again. 2021-01-09 20:59:58 -05:00
William Floyd
c293ed0b1a
nissan: Finish post. 2021-01-09 02:59:55 -05:00
William Floyd
e9fef4deb5
nissan: Fix link. 2021-01-09 01:40:04 -05:00
William Floyd
33766888b3
nissan: Add preliminary post on Nissan decoding. 2021-01-09 01:30:52 -05:00
William Floyd
07b890eea6
images_build: Add automatic rescaling, refresh hashes. 2021-01-09 00:34:48 -05:00
William Floyd
ec7e879aa7
image_build: Bugfixes. 2021-01-08 23:29:07 -05:00
William Floyd
c901ce64e8
midiMixer: Fix image link. 2020-07-05 21:25:20 -04:00
William Floyd
352a78107c
coffee: Add coffee maker post. 2020-07-05 02:04:07 -04:00
William Floyd
ee3a1882ae
images_build: Fix for non-local variable. 2020-07-05 02:03:35 -04:00
William Floyd
6ffb1731bb
rice: Rebuild SVG. 2020-07-05 00:22:30 -04:00
William Floyd
bc87f6d7e2
image_build: Fix. I don't know how this even worked before, it really should not have. 2020-07-05 00:21:32 -04:00
William Floyd
d2b6df03a5
rice: Fix image link. 2020-05-27 20:25:54 -04:00
William Floyd
f9a7a1031a
rice: Move and adapt dot graph, make script run scripts. 2020-05-27 19:37:18 -04:00
William Floyd
05f04a30ee
images-build: Handle errors. 2020-05-27 18:17:51 -04:00
William Floyd
5541b73e20
images_build: Check for some programs on start, make JPEG operations generic. 2020-05-27 18:10:57 -04:00
William Floyd
a08faeeb39
content: Use file hash as part of image processing. 2020-05-27 17:46:01 -04:00
William Floyd
4e41f311d2
rss: Remove full RSS, because new relative images don't link correctly. 2020-05-27 17:31:47 -04:00
William Floyd
f1140155f8
content: Add all images back to project. 2020-05-27 17:14:40 -04:00
William Floyd
ba282f9392
lfs: Include PNG files. 2020-05-27 17:14:00 -04:00
William Floyd
5633018ff8
clickbait: Change images to link to new format. 2020-05-27 17:12:28 -04:00
William Floyd
ce7d8cf501
Dockerfile: Add Dockerfile that I use to deploy the blog. 2020-05-27 17:01:03 -04:00
William Floyd
1068f1f728
images_copy: Remove old script. 2020-05-27 17:00:43 -04:00
William Floyd
2f140b021a
image_build: Add new script that will reasonably robustly handle various operations to files. 2020-05-27 17:00:06 -04:00
William Floyd
7f1bec89de
midiMixer: Use new image paths. 2020-05-27 16:59:45 -04:00
William Floyd
41a6848d87
content: Move to bundle format. 2020-05-26 00:09:34 -04:00
311 changed files with 3267 additions and 358 deletions

4
.dockerignore Normal file
View file

@ -0,0 +1,4 @@
.git
**/*.hash
**/src
public/

3
.gitattributes vendored
View file

@ -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
View file

@ -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
View file

5
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,5 @@
{
"cSpell.words": [
"Gluster"
]
}

7
Dockerfile Normal file
View 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

View file

@ -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/"

View file

@ -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.

View file

@ -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.
***
![Laying the groundwork](/images/reduced/clickbait/20190919_143530.jpg)
![Laying the groundwork](media/20190919_143530.webp)
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
***
![First print](/images/reduced/clickbait/20190919_224711.jpg)
![First print](media/20190919_224711.webp)
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
***
![T'was but a Fanta-sea](/images/reduced/clickbait/20191010_152148.jpg)
![T'was but a Fanta-sea](media/20191010_152148.webp)
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.
***
![Latching Track Installed](/images/reduced/clickbait/20191110_014623.jpg)
![Latching Track Installed](media/20191110_014623.webp)
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.
***
![Reel Mounted](/images/reduced/clickbait/20191115_090125.jpg)
![Reel Mounted](media/20191115_090125.webp)
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
***
![Plenty of Torque](/images/reduced/clickbait/20191118_032416.jpg)
![Plenty of Torque](media/20191118_032416.webp)
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
***
![It'll Send You Reeling!](/images/reduced/clickbait/20191120_224129.jpg)
![It'll Send You Reeling!](media/20191120_224129.webp)
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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

View file

BIN
content/posts/clickbait/media/src/20190919_143530.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
0fefa0a42b5ddc8f15e48e77cbadfa2fb8f25db06fc16e8e1afbc17f4e572505

BIN
content/posts/clickbait/media/src/20190919_213947.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
524f410f6f8d7febe879205b516ff2c2de9c2b2613bb42da8a3103e196763f73

BIN
content/posts/clickbait/media/src/20190919_224711.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
d0da1a5cca00a3d31b31769b9dc8f3c2ef5e69055d901fa8e6575ffa10d88f4a

BIN
content/posts/clickbait/media/src/20191003_000323.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
2ad738c50c7640a8bdcdcf5d5feeb8118bbd90343596bcdf50ce00c37e631544

BIN
content/posts/clickbait/media/src/20191004_160107.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
db26f30ae8b9406206394d6f08146d9a6c664da2f65ea30f7c0f493a2925c464

BIN
content/posts/clickbait/media/src/20191010_152148.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
55c2322f7bba7c7d29eb3e28ce2269662f4b2016daa9b240fb236e6821b692c0

BIN
content/posts/clickbait/media/src/20191025_194859.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
5051917955383bd82ec91d5b9082c3f1305782417ae6065e1cd1b80a220514f8

BIN
content/posts/clickbait/media/src/20191102_144426.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
3c91e3d30fb5b38e543b11f1a21982954078f8dd5d182805f5182a59c6469041

BIN
content/posts/clickbait/media/src/20191110_014623.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
d5e6e4baba1a9bc8858defe107721f069edf82e1c518326367a3d31f6ee8cedf

BIN
content/posts/clickbait/media/src/20191110_072012.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
6c9c220b1d695d76e5e3a93832fe14c49b3765ac93e4d971ebe9a981d33f3ce0

BIN
content/posts/clickbait/media/src/20191115_090125.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
24f6a28a746ea3d7213ee2ed2c40b22b756624331b24b486fd353b4abea576db

BIN
content/posts/clickbait/media/src/20191118_032416.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
e67916e0e2ea755a40fe7859b7e46fdfc1698c24d5da7a4898b7785dbe8d1754

BIN
content/posts/clickbait/media/src/20191120_224129.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
ef9c7801402a53ffc20bad84a5e5fb3587bbb2f2738d8d5df295d9e681070897

View 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.
![The Spoils of Goodwill](media/20200610_204856.webp)
***
Later that evening, opening the black box up (thankfully I had the correct triangular screwdriver head), I found very easily hackable innards.
![Poor lighting is the worst...](media/20200610_205351.webp)
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:
![Interception!](media/20200702_120309.webp)
![Perfboard](media/20200702_120302.webp)
![D1 Mini](media/20200702_120328.webp)
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.
![External USB Plug](media/20200702_120334.webp)
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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

View file

BIN
content/posts/coffee/media/src/20200610_204856.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
372a99d5662d499adccdd71c8110b8d459612110babf4099bf4d5bdd7370e329

BIN
content/posts/coffee/media/src/20200610_205351.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
d48ea9d5b0cfd9291c110a1beb64be4d7f76f62644986b49a969bc10cce9a7ca

BIN
content/posts/coffee/media/src/20200610_205841.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
f53659511bd33ac8c51a8f1fae74d24551c270e8fc6870553ce4edc04add95f2

BIN
content/posts/coffee/media/src/20200610_205847.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
cf91c706dec4682dbddc5be255fe9e5793c61941c0284c3bb7dae9e0fb592e80

BIN
content/posts/coffee/media/src/20200702_120123.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
526b6f7d067f17a0b593482823cb88024a0ad1417f905e7b61f1077773acd7aa

BIN
content/posts/coffee/media/src/20200702_120302.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
c259c61a1fc9b3554f5e2c3ed4a0318deb92ea013b665a32534f90c4f5b6d897

BIN
content/posts/coffee/media/src/20200702_120309.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
14bfcaec0739089a4bbbf57c78ad3ca93286cf402c9a987fcb63a23bfffddbf5

BIN
content/posts/coffee/media/src/20200702_120328.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
4404536aaf5f70f51fad0e9298ecf1ead5b97e52a3557d482f89d23f7ccba1ce

BIN
content/posts/coffee/media/src/20200702_120334.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
1ee1ad4b87c3a581e97879eb627e6c478972b86a83232fbd66173390de34fb80

View 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).

View 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

View 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>}}

View 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...

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
70c3922ade2b73a7a949d1015e738013903342a5860c7dae3525ff8b436e424c

View file

@ -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
***
![Orange Sherbert Dreams](/images/reduced/midiMixer/handwired/20190811_004928.jpg)
![Orange Sherbert Dreams](media/handwired/20190811_004928.webp)
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.
***
![It's Not Easy, Being Green](/images/reduced/midiMixer/v1/20200506_152328.jpg)
![It's Not Easy, Being Green](media/v1/20200506_152328.webp)
![Look Mum, Open Hardware!](/images/reduced/midiMixer/v1/20200506_152317.jpg)
![Look Mum, Open Hardware!](media/v1/20200506_152317.webp)
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.
![One In Hand](/images/reduced/midiMixer/v1/20200506_151852.jpg)
![One In Hand](media/v1/20200506_151852.webp)
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.
***
![It Ain't Much, But I'm Proud](/images/reduced/midiMixer/v1/20200506_152248.jpg)
![It Ain't Much, But I'm Proud](media/v1/20200506_152248.webp)
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.
![That Hair Is Bothering Me](/images/reduced/midiMixer/v1/20200506_151947.jpg)
![That Hair Is Bothering Me](media/v1/20200506_151947.webp)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

Binary file not shown.

View file

@ -0,0 +1 @@
80bebd4e51d1aaabde9777b00e87e415e73f4b5fe6a0acbf5f675fad2bab3ea9

Binary file not shown.

View file

@ -0,0 +1 @@
4e34713687f375c61df8d71d6e49adfb643f3f5df0ba8a919273e8b66b48e6f8

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more