Compare commits

..

No commits in common. "master" and "2020.05.24.1" have entirely different histories.

311 changed files with 358 additions and 3267 deletions

View file

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

3
.gitattributes vendored
View file

@ -1,5 +1,2 @@
*.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,6 +1,3 @@
[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
[submodule "themes/KeepIt"]
path = themes/KeepIt
url = https://github.com/Fastbyte01/KeepIt.git

View file

View file

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

View file

@ -1,7 +0,0 @@
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,89 +2,84 @@ baseURL = "//notmy.space/"
languageCode = "en"
defaultContentLanguage = "en"
title = "William Floyd"
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
theme = "KeepIt"
paginate = 12
enableEmoji = true
googleAnalytics = "UA-63647911-2"
enableRobotsTXT = true
canonifyURLs = true
[permalinks]
posts = "/:year/:month/:filename/"
[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
[params]
author = "William Floyd"
description = "William Floyd's personal website"
gravatar = "william.png2000@gmail.com"
dateFormat = "January 2, 2006"
since = 2018
colorScheme = "auto"
subtitle = "This is not MySpace, it's my space"
since = 2018
author = "William Floyd"
home_mode = ""
# If you want to implement a Content-Security-Policy, add this section
scriptsrc = [
"'self'",
"'unsafe-inline'",
"https://cdn.jsdelivr.net/"
]
prefetchsrc = ["'self'"]
[params.gravatar]
email = "william.png2000@gmail.com"
[taxonomies]
category = "categories"
series = "series"
tag = "tags"
author = "authors"
[params.social]
GitHub = "W-Floyd"
Linkedin = "william-floyd-906674190"
Email = "william.png2000@gmail.com"
Steam = "W-Floyd"
[[params.social]]
name = "Github"
icon = "github"
weight = 1
url = "https://github.com/W-Floyd/"
[[params.social]]
name = "LinkedIn"
icon = "linkedin"
weight = 2
url = "https://www.linkedin.com/in/william-floyd/"
[params.share]
[[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/"
[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

View file

@ -1,8 +1,8 @@
---
title: "About"
date: "2023-12-15"
date: "2018-06-19"
---
I am William Floyd, this is my blog.
I currently work as an Associate Project Manager at Engenious Design.
I am currently a Mechanical Engineering student at LeTourneau.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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

@ -1 +0,0 @@
0fefa0a42b5ddc8f15e48e77cbadfa2fb8f25db06fc16e8e1afbc17f4e572505

Binary file not shown.

View file

@ -1 +0,0 @@
524f410f6f8d7febe879205b516ff2c2de9c2b2613bb42da8a3103e196763f73

Binary file not shown.

View file

@ -1 +0,0 @@
d0da1a5cca00a3d31b31769b9dc8f3c2ef5e69055d901fa8e6575ffa10d88f4a

Binary file not shown.

View file

@ -1 +0,0 @@
2ad738c50c7640a8bdcdcf5d5feeb8118bbd90343596bcdf50ce00c37e631544

Binary file not shown.

View file

@ -1 +0,0 @@
db26f30ae8b9406206394d6f08146d9a6c664da2f65ea30f7c0f493a2925c464

Binary file not shown.

View file

@ -1 +0,0 @@
55c2322f7bba7c7d29eb3e28ce2269662f4b2016daa9b240fb236e6821b692c0

Binary file not shown.

View file

@ -1 +0,0 @@
5051917955383bd82ec91d5b9082c3f1305782417ae6065e1cd1b80a220514f8

Binary file not shown.

View file

@ -1 +0,0 @@
3c91e3d30fb5b38e543b11f1a21982954078f8dd5d182805f5182a59c6469041

Binary file not shown.

View file

@ -1 +0,0 @@
d5e6e4baba1a9bc8858defe107721f069edf82e1c518326367a3d31f6ee8cedf

Binary file not shown.

View file

@ -1 +0,0 @@
6c9c220b1d695d76e5e3a93832fe14c49b3765ac93e4d971ebe9a981d33f3ce0

Binary file not shown.

View file

@ -1 +0,0 @@
24f6a28a746ea3d7213ee2ed2c40b22b756624331b24b486fd353b4abea576db

Binary file not shown.

View file

@ -1 +0,0 @@
e67916e0e2ea755a40fe7859b7e46fdfc1698c24d5da7a4898b7785dbe8d1754

Binary file not shown.

View file

@ -1 +0,0 @@
ef9c7801402a53ffc20bad84a5e5fb3587bbb2f2738d8d5df295d9e681070897

View file

@ -1,104 +0,0 @@
---
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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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

@ -1 +0,0 @@
372a99d5662d499adccdd71c8110b8d459612110babf4099bf4d5bdd7370e329

Binary file not shown.

View file

@ -1 +0,0 @@
d48ea9d5b0cfd9291c110a1beb64be4d7f76f62644986b49a969bc10cce9a7ca

Binary file not shown.

View file

@ -1 +0,0 @@
f53659511bd33ac8c51a8f1fae74d24551c270e8fc6870553ce4edc04add95f2

Binary file not shown.

View file

@ -1 +0,0 @@
cf91c706dec4682dbddc5be255fe9e5793c61941c0284c3bb7dae9e0fb592e80

Binary file not shown.

View file

@ -1 +0,0 @@
526b6f7d067f17a0b593482823cb88024a0ad1417f905e7b61f1077773acd7aa

Binary file not shown.

View file

@ -1 +0,0 @@
c259c61a1fc9b3554f5e2c3ed4a0318deb92ea013b665a32534f90c4f5b6d897

Binary file not shown.

View file

@ -1 +0,0 @@
14bfcaec0739089a4bbbf57c78ad3ca93286cf402c9a987fcb63a23bfffddbf5

Binary file not shown.

View file

@ -1 +0,0 @@
4404536aaf5f70f51fad0e9298ecf1ead5b97e52a3557d482f89d23f7ccba1ce

Binary file not shown.

View file

@ -1 +0,0 @@
1ee1ad4b87c3a581e97879eb627e6c478972b86a83232fbd66173390de34fb80

View file

@ -1,102 +0,0 @@
---
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

@ -1,150 +0,0 @@
---
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

@ -1,184 +0,0 @@
---
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

@ -1,320 +0,0 @@
---
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

@ -1 +0,0 @@
70c3922ade2b73a7a949d1015e738013903342a5860c7dae3525ff8b436e424c

Binary file not shown.

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

@ -1 +0,0 @@
80bebd4e51d1aaabde9777b00e87e415e73f4b5fe6a0acbf5f675fad2bab3ea9

Binary file not shown.

View file

@ -1 +0,0 @@
4e34713687f375c61df8d71d6e49adfb643f3f5df0ba8a919273e8b66b48e6f8

Binary file not shown.

View file

@ -1 +0,0 @@
b1f7de3b630c01de2c09bf0355706ea6801b429651ff73fa8f1d69d979106481

Binary file not shown.

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