Author SHA1 Message Date
nicholas e70b671062 finish post (refs #15) 2025-08-12 11:42:22 -05:00
nicholas 3646825485 add new draft post (refs #9) 2025-08-07 18:58:50 -05:00
3 changed files with 24 additions and 301 deletions
@@ -1,7 +1,7 @@
+++
categories = ["build"]
tags = ["bicycle"]
date = 2025-08-12T12:15:00-05:00
date = 2025-08-07T08:00:00-05:00
description = ""
draft = false
slug = "bicycle-headlamp"
@@ -14,7 +14,7 @@ Nighttime bicycle rides in the summer are ideal:
- 🚘 little traffic
- 🦝 nocturnal wildlife
But it is not easy to see in the dark, so I bring a headlamp and *okay, fine, this works*. With my current headlamp I can see and be seen just fine. But there are some limitations. I see wonderfully directly ahead of me in the narrow cone of light provided, but at the edges of this light cone I see practically nothing at all, as though I am looking through a paper towel roll. The beam pattern is optimized for riding in a straight line, with little regard for what lies in the periphery. **I would like a greater field of view, so I will need a lamp with a wide beam pattern.**
But it is not easy to see in the dark, so I bring a headlamp and okay, fine, this works. With my current head lamp I can see and be seen just fine. But there are some limitations. I see wonderfully directly ahead of me in the narrow cone of light provided, but at the edges of this light cone I see practically nothing at all, as though I am looking through a paper towel roll. The beam pattern is optimized for riding in a straight line, with little regard for what lies in the periphery. I would like a greater field of view, so I will need a lamp with a wide beam pattern.
## 🔦 Headlamp
I start by selecting the headlamp. This is the most important component, and everything will revolve around it. My selection criteria is simple. The light must have these features:
@@ -36,20 +36,24 @@ I had to settle for the **OPL5 Motorcycle LED Headlamp**:
| Brightness | 3000 lm |
| Color Temperature | 6500K (Cool White) |
**This will have to do**.
{{< image src="images/opl5-motorcycle-led-headlamp.png" >}}
{{< image
src="images/beam-pattern.JPG"
caption="OPL5 Beam against the wall" >}}
## 🔋 Battery Sizing
Since the headlamp consumes 48 W, I need a battery that can sustain this load for a couple of hours without totally draining the battery. I can see how long a given battery will endure.
Notice the sharp beam cutoff at the top. This is what allows me to have a very bright headlamp while also not blinding oncoming traffic. Also, the beam gradient at the bottom transitions from very bright to very dim, in a manner that maximizes usable light. It concentrates maximum light near the upper cutoff where it will disperse across a large surface area at long distances, while minimizing output in the near and mid field, where the illuminated surface area should be relatively small.
- $t$ = run time (hr)
- $E_\text{battery}$ = battery energy (Wh)
- $p_\text{load}$ = LED headlamp power (W)
**This will do**.
$$
t = \frac{12.8 \text{ V} \cdot 16 \text{ Ah}}{48 \text{ W}} = 4.27 \text{ hr}
$$
---
**This will work**. It is a comfortable, if not excessive, amount of energy for the headlamp.
## 🧰 Case
I selected a cheap weatherproof case from *Harbor Freight Tools*. It will be large enough to accommodate many sizes of batteries, since battery packs of the nature I seek are almost always composed of a bunch of even smaller batteries, typically the 18650 type batteries. The dimensions of this battery type are also its namesake: **18 mm dia. × 65 mm l**.
@@ -63,40 +67,24 @@ I mention all of this because the height dimension of the battery packs are almo
{{< image src="images/apache-1800-case.png" >}}
---
## 🔋 Battery
Since the headlamp consumes 48 W, I need a battery that can sustain this load for a couple of hours without totally draining the battery. I can see how long a given battery will endure.
- $t$ = run time (hr)
- $E_\text{battery}$ = battery energy (Wh)
- $P_\text{load}$ = LED headlamp power (W)
$$
t = \frac{12.8 \text{ V} \cdot 16 \text{ Ah}}{48 \text{ W}} = 4.27 \text{ hr}
$$
I selected a cheap, unremarkable 12 V battery with a capacity of 16Ah.
✅ This will be fine.
{{< image src="images/nermak-12v-16Ah-LiFePO4.png" >}}
**This will work**. It is a comfortable, if not excessive, amount of energy for the headlamp.
---
## 🔌 Switches and Ports
I splurged on a nice weatherproof SPST switch and mounting bracket.
{{< image src="images/bss-contura-iii-spst.png" >}}
{{< image src="images/bss-contura-iii-mounting-bracket.png" >}}
The port that will feed power to the headlamp power is some kind of 'SAE' connector, which as far as I can tell do not actually comply with any official standard. They are used for a lot of things in weird cheap Chinese electronics, and I could have selected a better connector. I selected this mostly because it matches the connector on my battery charger and it is cheap and ubiquitous. It will be adequate.
The port that will feed power to the headlamp power is some kind of 'SAE' connector, which as far as I can tell do not actually comply with any official standard. They are used for a lot of things in weird cheap Chinese electronics, and I could have selected a better connector. I selected this mostly because it matches the connector on my battery charger and it is cheap and ubiquitous.
{{< image src="images/SAE-connector-socket.jpg" >}}
---
## 🔩 Parts List
| Part |
|-|
@@ -106,26 +94,9 @@ The port that will feed power to the headlamp power is some kind of 'SAE' connec
| SAE Power Socket Port |
| Inline Blade Fuse Holder + 5 A Fuse |
| Blue Sea Systems Contura III OFF-ON SPST Switch + Mounting Panel |
| Double-sided adhesive tape |
| Spade connectors |
| Shrink tube |
---
## 🛠️ Assembly
Now for final assembly. This is all very simple and I ran into no issues.
- Applied double-sided adhesive tape to fasten the battery enclosure to the box
- Soldered on spade connectors to wires between switch and battery
- Installed inline fuse
- Sealed the power port and switch mounting holes with silicone
- Removed the battery enclosure lid since the battery terminals were ≈ 1 mm proud of the battery box lid. The battery box would still close, but it was straining the plastic and the weather sealing would be compromised.
{{< image
src="images/battery-box-open.JPG"
caption="Battery box inside" >}}
Here is a **wiring diagram** of the circuit.
All that remains is to do final assembly. This is all very simple and I ran into no issues. Here is a **wiring diagram** of the circuit.
{{< image src="images/bicycle-headlamp-wiring-diagram.svg" >}}
@@ -136,33 +107,17 @@ Here is a **wiring diagram** of the circuit.
| SW1 | SPST Switch |
| LED1 | 48 W |
- Applied double-sided adhesive tape to fasten the battery enclosure to the box
- Soldered on spade connectors to wires between switch and battery
- Installed inline fuse
- Sealed the power port and switch mounting holes with silicone
- Removed the battery enclosure lid since the battery terminals were ≈ 1 mm proud of the battery box lid. The battery box would still close, but it was straining the plastic and the weather sealing would be compromised.
{{< image
src="images/battery-box-power-port.JPG"
caption="Battery box power port" >}}
I strap the battery box to the rear cargo rack with hook and loop straps.
{{< image
src="images/battery-box-switch.JPG"
caption="Battery box switch" >}}
That is all.
{{< image
src="images/battery-box-mounted.JPG"
caption="Battery box fastened to the rear cargo rack with hook and loop straps" >}}
{{< image
src="images/headlamp-mounted.JPG"
caption="Headlamp on handlebars" >}}
---
## 🚴 Test Drive
All that remains is the test drive.
{{< image src="images/headlamp-night-test-drive.jpg" >}}
{{< image
src="images/headlamp-night-test-drive.jpg"
caption="Wide beam width" >}}
🎉 **It works!**
✅ Done.
@@ -1,207 +0,0 @@
+++
categories = ["software"]
tags = ["router","opnsense"]
date = 2025-08-27T18:30:00-05:00
description = ""
draft = false
slug = "router-build"
title = "🔀 Router Build"
author = "nicholas"
+++
My router (**Netgear R6400v2**) lacks many of the features I would like to use and become familiar with:
- VLANs
- Advanced routing, firewall
- Monitoring, logging, alerts
- etc.
**I need a new router.**
I have a few options from here:
1.**Write custom firmware to existing router** (*DD-WRT, OpenWRT, Tomato, etc.*)
- Fun
- Free
- Too much jank
2.**Buy new hardware**
- Very easy setup
- Boring
- 💲 Could require expensive/high-end router hardware
3.**Repurpose existing hardware**
- Fun
- Makes use of an unused **Dell OptiPlex 5050 Micro**
- Can run proper router OS **OPNsense**
- Repurpose router as wireless access point
---
## 🪵 Router-on-a-stick (ROAS)
My VM host (where I will build my router) has only a single NIC, with only one physical port. That means I cannot replicate the exact behavior of ordinary consumer routers, which are typically configured with a dedicated WAN port, and several dedicated LAN ports. The router simply routes between the two. Very simple. I need to find a way to replicate the *function* of such a router without the same *hardware*.
I have a couple of options:
1. ❌ Configure the **virtual switch** on my VM host to perform 802.1Q VLAN tagging for router VM.
- Free, no additional hardware required
2. ✅ Configure a **managed physical switch** to handle 802.1Q VLAN tagging and trunking to the router
- Gain additional physical ports
- 💲 Addtional hardware required
I want the extra ports! I got a **Netgear GS108E-400NAS**. For no other reason than it was available at my local *Best Buy*.
---
## 🖧 Logical Network Topology
This diagram describes approxmiately what I my network will look like:
```mermaid
graph TD
isp["🌐ISP"]
modem["📡Modem"]
switch["🔀Switch"]
subgraph vm-host["VM Host"]
router["🛡️Router (OPNsense)"]
end
wap["🛜WAP"]
nas["🗄️NAS"]
workstation["🖥️Workstation"]
subgraph wireless["Wireless Devices"]
laptop["💻Laptop"]
phone["📱Phone"]
printer["🖨️Printer"]
end
isp --- modem
modem --- switch
switch --- |"🪵 Trunk (VLANs 10,100)"| router
switch --- wap
switch --- nas
switch --- workstation
wap -.- wireless
```
---
## 🔀 Switch Setup & Port VLAN Assignment Table
- First, I need to choose a subnet for my network and assign my switch an IP accordingly. I chose 10.0.0.0/8 subnet. It just looks good.
- Next I cofigure my switch with a **trunk port**. This port will link to the router and carry multiple VLANs: **VLAN 10** (LAN), **VLAN 100** (WAN). This allows my router to distinguish between WAN and LAN with just one physical port. Instead of a phyiscal port to ditinguish WAN and LAN, the distinction is made virtually using VLAN tags.
- This means I will also need to configure a separate port for VLAN 100 (modem/ISP uplink), so that all traffic on that port is tagged and forwarded as WAN traffic.
| Port | Device | VLAN Mode | PVID | Tagged VLANs |
|-|-|-|-|-|
| 1 | Router | Trunk | 10 | 10,100 |
| 2 | Workstation | Access | 10 | - |
| 3 | NAS | Access | 10 | - |
| 4 | WAP | Access | 10 | - |
| 5 | - | Access | 10 | - |
| 6 | - | Access | 10 | - |
| 7 | - | Management | 1 | - |
| 8 | Modem | Access | 100 | - |
---
**Switch VLAN tagging**
```mermaid
flowchart TD
lan["🏠LAN"]
modem["🌐Modem/ISP"]
switch[🔀Switch]
subgraph router["🛡️Router"]
wan_interface["🌐WAN Interface"]
lan_interface["🏠LAN Interface"]
end
lan -- "`
*🗅untagged*
🔵access port **VLAN 10**
`" --> switch
modem -- "`
*🗅untagged*
🔵access port **VLAN 100**`" --> switch
switch -- "*🏷️tagged* VLAN 10" --> lan_interface
switch -- "*🏷️tagged* VLAN 100" --> wan_interface
```
✅ Done. Now I configure a VM for the router.
---
## 🖥️ VM Configuration
I need to configure a VM to serve as a router:
- COnfigure VM specs:
- 20 GB vdisk
- 3 GB RAM
- 1 vCPU
- Install OPNsense OS
- Configure VM network adapter with static MAC address (spoof old netgear router MAC, keep current DHCP IP)
- Configure host OS network adapter to carry VLAN ID 10 only
- Configure VM network adapter to carry VLANs ID 10,100
✅ Done. Now I can configure OPNsense.
---
## 🛡️ OPNsense
{{< image
src="images/OPNsense-dashboard.png"
caption="OPNsense Dashboard" >}}
##### Interfaces
According to the plan, I need to configure OPNsense with an interface for each VLAN I configured:
- VLAN **10** for **LAN**
- VLAN **100** for **WAN**
##### DNSMasq DHCP
Since I want most of my devices to be assigned IPs dynamically, I enable DHCP on the LAN interface.
- Start address: 10.0.10.3
- End address: 10.0.10.100
- 10.0.10.100 - 10.0.10.200 are reserved for static / wired devices.
##### Unbound DNS
I also want to use my router as a DNS server for local DNS resolution, so I enable **Unbound DNS**. This is where I can configure A records (host override), and CNAME records (alias).
**For example:**
| Record Type | Name | Value |
|-|-|-|
| A | proxy.internal.domain.com | 10.0.10.100 |
| CNAME | git.domain.com | proxy.internal.domain.com |
##### Query Forwarding
Now that I have given my wired devices static IPs, I can do query forwarding to Pi-Hole. This will enable network-wide ad blocking.
```mermaid
flowchart LR
client[💻Client] --> router-dns["`
🛡️Router
(Local DNS)
`"]
router-dns --> pihole[🕳️Pi-hole]
pihole --> upstream["`
☁️ Upstream DNS
(e.g. 8.8.8.8)`"
]
```
##### Firewall - GeoIP
I use [MaxMind GeoIP database](https://AccountID:LicenseKey@download.maxmind.com/geoip/databases/GeoLite2-Country-CSV/download?suffix=zip) to create a firewall alias. Then I configured a firewall rule on WAN interface which blocks any IP that matches those configured in the alias. I am blocking IPs from most countries.
This nearly eliminates unwanted traffic from annoying and/or malicious bots scanning and scraping my network
**MaxMind GeoIP database**:`https://AccountID:LicenseKey@download.maxmind.com/geoip/databases/GeoLite2-Country-CSV/download?suffix=zip`
🎉 It works!
{{< video
src="videos/router-traffic-graph-live.mp4"
width="100%"
>}}
✅ Done.
@@ -1,25 +0,0 @@
+++
categories = ["build"]
tags = []
date = 2025-10-28T16:31:00Z
description = ""
draft = false
slug = "truck-bed-rails-repair"
title = "🛻 Truck Bed Rails Repair"
author = "nicholas"
+++
## Problem
I removed the ladder rack from my truck bed. It left behind scratched paint, bolt holes, and some rust.
## Parts / Equipment
-
## Steps
- wire brush away rust
- clean with isopropyl alcohol
- apply primer
- apply top coat (opt)
✅ Done.