Helpless Automation

Application Development

How to setup DHCP on the PiHole with a TP-Link Router

My set up is:

  • PiHole running BookWorm OS
  • TP-Link Router Archer AXE5400

I also had issues running DHCP from the PiHole using a TP-Link router. The problem is that if you reserve an IP for your PiHole, like 192.168.0.2, in the router but then turn off DHCP, the PiHole will not get assigned to 192.168.0.2 because reservations need DHCP running on the TP-Link router for the assignment to work.

One way of solving this is to set the DHCP IP address pool on the router from 192.168.0.2 to 192.168.0.2 while keeping the DHCP on. This will essentially only lease IP to the router and nothing else. Then, turn on DHCP on the PiHole. That should work.

I ended up setting a static IP on the PiHole to 192.168.1.2. Then you can turn off DHCP on the router and turn it on in the PiHole, and walla, everything seems to be working. I also disabled the WiFi on the PiHole because it’s hard to connect to the router. I am using BookWork OS on the PiHole.

Remember to restart your modem, router, and PiHole. I noticed issues if the devices were not restarted.

Here is a post I wrote on how to set a static IP on the PiHole that has BookWork OS:
https://www.helplessautomation.com/set-static-ip-with-pi-hole-dns-on-raspberry-pi/

For both solutions above, remember to set the router’s primary and secondary DNS servers to point to the PiHole IP.

I hope this helps. Let me know if anyone has any questions.

HLC

Set Static IP with Pi-hole DNS on Raspberry Pi

Set Static IP with Pi-hole DNS on Raspberry Pi (Bookworm)

These instructions guide you through setting a static IP address (192.168.1.2) on a Raspberry Pi running Bookworm OS using nmtui, with the Pi configured to use itself as the DNS server for Pi-hole.

Prerequisites

  • Raspberry Pi OS Bookworm is installed.
  • You have terminal access (via SSH or directly).
  • NetworkManager is installed (default in Bookworm).
  • Pi-hole is installed and will use 192.168.1.2 as its address.
  • You router will use 192.168.1.1 as its address.

Steps to Configure

  1. Open the Terminal

    Log in to your Raspberry Pi and open a terminal.

  2. Launch nmtui

    Run this command:

    sudo nmtui
  3. Navigate to “Edit a Connection”

    Use arrow keys to select “Edit a connection” and press Enter.

  4. Select Your Network

    Highlight your connection (e.g., Wired connection 1 for Ethernet or your Wi-Fi name) and press Enter.

  5. Configure IPv4 Settings

    Scroll to “IPv4 CONFIGURATION”, change from Automatic to Manual, and press Enter.

  6. Set Static IP and DNS
    • Addresses: Enter 192.168.1.2/24 (subnet mask 255.255.255.0).
    • Gateway: Enter your router’s IP (e.g., 192.168.1.1).
    • DNS servers: Enter 192.168.1.2 (the Pi’s own IP for Pi-hole).
  7. Save the Configuration

    Scroll to “OK” and press Enter, then Esc to return to the main menu.

  8. Exit nmtui

    Select “Quit” and press Enter.

  9. Restart the Network

    Apply changes with:

    sudo systemctl restart NetworkManager

    Or reboot:

    sudo reboot
  10. Verify the Static IP

    Check with:

    ip addr

    Ensure 192.168.1.2 is assigned to your interface (e.g., eth0 or wlan0).

Example Configuration

  • Static IP: 192.168.1.2/24
  • Gateway: 192.168.1.1
  • DNS: 192.168.1.2 (Pi-hole)
Notes:
  • Adjust the gateway to match your network’s router IP.
  • Ensure no other device uses 192.168.1.2 to avoid conflicts.
  • If Pi-hole isn’t working, verify it’s running (sudo systemctl status pihole-FTL).
  • If nmtui isn’t available, install it with: sudo apt install network-manager.

Updated: March 02, 2025 | Powered by xAI

Raspberry Pi OS with Pi-Hole Installation





 

Raspberry Pi with Pi-Hole Setup Instructions

I recently upgraded my Pi-Hole OS from Buster (v10) to Bookworm (v12). Even though I did this a few years back, it is hard to remember the steps needed to accomplish the goal. Especially for those that are more versed in Windows OS than Linux type OS. This time I decided to document the procedure.

1. SD Card Setup

Updates the system and configures basic settings on the SD card.

sudo apt update && sudo apt full-upgrade -y
sudo raspi-config  # Timezone, SSH, expand filesystem
sudo reboot

2. Fix SSH

Removes old SSH key from Windows to reconnect after reinstall.

ssh-keygen -R 192.168.1.4  # On Windows, adjust IP

3. Overclock (Fix Flickering)

Boosts CPU/GPU speeds to fix screen flicker, later optimized.

sudo nano /boot/firmware/config.txt
# Initial: over_voltage=6, arm_freq=2100, gpu_freq=750
# Optimized: over_voltage=4, arm_freq=1800, gpu_freq=750
sudo reboot

4. USB SSD Boot

Enables SSD booting and clones SD card to SSD for faster performance.

sudo rpi-eeprom-update -a && sudo reboot
lsblk  # Verified your source and target drive addresses: SD=/dev/mmcblk0, SSD=/dev/sda
sudo dd if=/dev/mmcblk0 of=/dev/sda bs=4M status=progress && sudo sync
sudo shutdown -h now
sudo raspi-config  # Expand filesystem on SSD
sudo reboot

5. Swap File Tweaks

Adjusts virtual memory: removed, then set to 1GB, later 512MB.

sudo swapoff -a          # Turn off all active swap spaces
sudo systemctl stop dphys-swapfile  # Stop the swap management service
sudo apt remove dphys-swapfile      # Uninstall the swap service
sudo rm /var/swap        # Remove the swap file (optional)
free -h                  # Verify swap is 0B (no reboot needed)
# Later: CONF_SWAPSIZE=1024
sudo apt install -y dphys-swapfile
sudo nano /etc/dphys-swapfile  # CONF_SWAPSIZE=1024
sudo systemctl start dphys-swapfile
# Later: CONF_SWAPSIZE=512
sudo systemctl stop dphys-swapfile 
sudo nano /etc/dphys-swapfile  # CONF_SWAPSIZE=512
sudo systemctl start dphys-swapfile

6. Enable RDP

Installs xrdp for remote desktop access from Windows.

sudo apt install -y xrdp
sudo systemctl enable xrdp && sudo systemctl start xrdp
sudo reboot

7. Install Pi-Hole

Sets up Pi-Hole as a network-wide ad blocker and DNS server.

sudo apt update
curl -sSL https://install.pi-hole.net | bash  # Follow installer prompts
sudo pihole -a -p  # Set admin password


That is it, let me know if you have any questions. HLC.

 

Encompass Best Practices for Development and Deployment

  1. Formulate Acceptance Criteria
    • Analyze the problem we are trying to solve
    • Write up a one or two-page Requirements Document
      • Include a diagram if possible
      • Use the document when validating requirements with the Business
      • Use the document when communicating with QA and Training
    • Come up with a solution
      • Reach out to fellow Admins and/or Developers to brainstorm
      • Document components that will make up the solution
        • plugin, codebase, custom fields, screens, etc.
  2. Come up with a Business Communication Plan
    • Do we need Compliance approval?
    • What users will be affected by the change?
    • Do we need Training involved?
    • Do we create a wiki that will help explain the feature?
    • Inform Support Teams
  3. Once Development is completed, the feature must pass:
    • Unit testing by the developer/admin
    • Dev Demo to Stakeholders
    • Code Review including
      • forms, code-behind
      • custom fields, biz rules
      • custom C# code
    • QA Testing by QA 
    • User Acceptance Testing by Stakeholder
    • Explicit Approval by Stakeholders Ideally via Email with Product Owner and Scrum Master Copied in the email
  4. Come up with a Deployment Plan – Build a list of steps that will be needed in order to deploy the feature depending on the work that was done. For Example:
    • Deploy Master Plugin
    • Import UW Summary Form
    • Import 2 Modified Custom Fields
      • CX.ModifiedFieldOne
      • CX.ModifiedFieldTwo
    • Import 3 New Custom Fields
      • CX.CustomFieldOne
      • CX.CustomFieldTwo
      • CX.CustomFieldThree
    • Import 1 modified Business Rule
      • Auto-Populate Closing Date Rule
  5. Come up with a Roll Back Plan – Build a list of steps that will be needed to put things back the way they were before your deployment. For Example:
    • Rollback Master Plugin
      • Get the latest from Master
      • Increment Version Number
      • Deploy Master Plugin
    • Rollback UW Summary Form
      • Import from Backup made just before deployment
      • Rollback 2 Modified Custom Fields
      • Import from Backup made just before deployment
      • CX.ModifiedFieldOne
      • CX.ModifiedFieldTwo
    • Remove New Custom Fields (if needed)
      • Delete CX.CustomFieldOne
      • Delete CX.CustomFieldTwo
      • Delete CX.CustomFieldThree
  6. Execute Rollback Preparation – For Example:
    • Backup UW Summary form by exporting the form only from Input Form Builder
    • Back up existing Custom Fields and Biz Rules modified by exporting them from Input Form Builder
    • Add all backups in the Jira Story that governs the feature you are working on (source control, separate conversation)
  7. Execute Deployment – Pair Up with someone whenever possible
    • Announce deployment in Release Chat/Team Chat
      • Announce all components and services 
    • Stage your Deployment objects (separate best practice) 
    • Execute Deployment Plan
    • Smoke Test (separate conversation)
    • Be aware of reports of things not working as expected in and around the area that your feature touched
    • Make sure to over Communicate in Release Chat or Telephone and not Email if you have questions or input on any existing issues or outages post your deployment

Windows 10 and lein self-install fails on Powershell – Solved

I am starting to learn Clojure and wanted to set up Leiningen on my Windows 10 professional.

Here is how I solved the Windows Security problem that was preventing me from downloading the github zip file needed.

Here is hoping that someone finds this solution helpful.

Using PowerShell running as Administrator, I was having trouble getting my REPL going:

PS C:\> lein repl

C:\Users\{YourUserName}\.lein\self-installs\leiningen-2.8.1-standalone.jar can not be found.
You can try running "lein self-install"
or change LEIN_JAR environment variable
or edit lein.bat to set appropriate LEIN_JAR path.

Next, I tried to command lein to self-install:

PS C:\> lein self-install
Downloading Leiningen now...
Exception calling "DownloadFile" with "2" argument(s): "The request was aborted: Could not create SSL/TLS secure
channel."
At line:1 char:145
+ ... che]::DefaultNetworkCredentials; $client.DownloadFile($a, $f)} "https ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WebException

Failed to download https://github.com/technomancy/leiningen/releases/download/2.8.1/leiningen-2.8.1-standalone.zip

It is possible that the download failed due to "powershell",
"curl" or "wget"'s inability to retrieve GitHub's security certificate.
The suggestions below do not check certificates, so use this only if
you understand the security implications of not doing so.

The PowerShell failed to download the latest Leiningen version.
Try to use "curl" or "wget" to download Leiningen by setting up
the HTTP_CLIENT environment variable with one of the following
values:

a) set HTTP_CLIENT=wget --no-check-certificate -O
b) set HTTP_CLIENT=curl -f -L -k -o

NOTE: Make sure to *not* add double quotes when setting the value
of HTTP_CLIENT

The suggested fix as you can see deals with getting around our inability to get GitHub’s security certificate.

This is really not the right thing to do from a Security perspective. The real problem as I understand is that GitHub only supports TLS 1.2.

In order for us to use PowerShell with TLS 1.2, I needed to do the following:

  1. In power shell, type in the following to find where your PowerShell profile lives:

    PS C:\> $profile
    C:\Users\{YourUserName}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

  2. I went to that location but did not see a file. I ran this test to see if my PowerShell detected a profile file:

    PS C:\> test-path $profile
    False

    False means that the file is not there, but we already knew that right?

  3. Next, I created the PowerShell profile file like so:

    PS C:\> new-item -path $profile -itemtype file -forceDirectory: C:\Users\YourUserName\Documents\WindowsPowerShell

    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a---- 10/27/2018 2:38 PM 0 Microsoft.PowerShell_profile.ps1

  4. Once that command finished casting its spell, I did another test-path:

    PS C:\> test-path $profile
    True

    It sees my profile ps1 script now! Progress is Good.

  5. Next, using Notepad, I opened the Microsoft.PowerShell_profile.ps1 file. It was empty. I added the following line which allows PowerShell to use TLS 1.2 and saved the file:

    [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
  6. With renewed confidence, I tried to command lein to self-install once more:

    PS C:\> lein self-install
    Downloading Leiningen now...
    PS C:\>

    No news is good news. I thought. No error this time. What happened? Did it self-install this time?

  7. The only way to find out was to try running my repl once again, fingers crossed:

    PS C:\> lein repl
    Retrieving org/clojure/tools.nrepl/0.2.12/tools.nrepl-0.2.12.pom from central
    Retrieving org/clojure/pom.contrib/0.1.2/pom.contrib-0.1.2.pom from central
    Retrieving org/sonatype/oss/oss-parent/7/oss-parent-7.pom from central
    Retrieving clojure-complete/clojure-complete/0.2.4/clojure-complete-0.2.4.pom from clojars
    Retrieving org/clojure/tools.nrepl/0.2.12/tools.nrepl-0.2.12.jar from central
    Retrieving clojure-complete/clojure-complete/0.2.4/clojure-complete-0.2.4.jar from clojars
    nREPL server started on port 60194 on host 127.0.0.1 - nrepl://127.0.0.1:60194
    REPL-y 0.3.7, nREPL 0.2.12
    Clojure 1.8.0
    Java HotSpot(TM) Client VM 1.8.0_191-b12
    Docs: (doc function-name-here)
    (find-doc "part-of-name-here")
    Source: (source function-name-here)
    Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
    Results: Stored in vars *1, *2, *3, an exception in *e

     

    user=>


    Success!!!!


Now you know how to overcome this problem Take care and Happy coding.

References:

https://leiningen.org/

StackOverflow

Microsoft Tech Net

Outlook Redemption (Redemption.dll) and Background Threading do not mix.

Outlook Redemption is a very nice library which allows access to many Outlook functions many of those not exposed via the Outlook object model. We are currently using Redemption in our application to add outlook appointments with reminders, pop email messages with pre-populated information, etc.

We wrapped the Redemption.dll into our own Singleton class and called it OutlookRedemption as you will see in the following code examples.

We have had a couple of situations where emailing from our application stops working or works intermittently and in both of those occurrences, the culprit was using the API in a back ground thread.

Continue reading “Outlook Redemption (Redemption.dll) and Background Threading do not mix.”

ClickOnce Deployment Architecture

While continuing my research and learning of ClickOnce deployment, I came across a very interesting page that explains Click Once Deployment Architecture. The article describes how a ClickOnce installation is physically installed on a client computer.

Application Publication

Each application publication has:

  • A deployment manifest – A deployment manifest is an XML file that describes a ClickOnce deployment, including the identification of the current ClickOnce application version to deploy.
  • An application manifest – An application manifest is an XML file that describes an application that is deployed using ClickOnce.
  • All of the application files for that version.
The client computer must have the .NET framework 2.0 or later installed in order to do a ClickOnce deployment to that computer. The .NET framework can be deployed in a variety of ways including the ClickOnce Bootstrapper.

Continue reading “ClickOnce Deployment Architecture”

2011 Daytona 500 – NASCAR 14 Car Crash –

In Daytona Beach, Florida today, the 2011 edition of the Daytona 500 Sprint Cup series race was ran. The winner was Trevor Bayne, who making his first start at Daytona became the youngest driver ever to win the famed race.  Trevor celebrated his 20th birthday yesterday. The former youngest driver to win a Daytona 500 was Jeff Gordon who was 25 years old at the 1997 event.

Trevor Bayne gave Wood Brothers Racing team their first Daytona 500 victory since 1976 and only the fourth overall victory in the last 20 years.

“Am I dreaming? Is this real? I don’t even know where to go.” said the stunned driver to his team at the end of the race as he drove his #21 Motor Craft Ford to victory lane.

2011 Daytona 500 Results

Here is a link to video of a 14-car crash which was the result of team mates Michael Waltrip and David Reutimann as they bumped on a “push” maneuver.

 

Learn more about NASCAR: NASCAR 101

News Sources: Stats.Com , FanHouse.Com

ClickOnce Deployment – Deploying multiple versions of the same application

According to Wikipedia, ClickOnce is a Microsoft technology that enables the user base to install and run a Windows Application by clicking a link in a web page. ClickOnce is a component of Microsoft .NET Framework 2.0 and later and it supports deploying applications made with Windows Forms or Windows Presentation Foundation.

ClickOnce attempts to bring the ease of deployment similar to web applications to the Windows user base. ClickOnce aims to solve three common problems with conventional methods of deploying an application:

  1. The sometimes difficulty of updating a deployed application.
  2. The impact of an application on a user’s computer system.
  3. The need for administrator permission in order to install or update the application.

WPF coding mutually exclusive Check Boxes with Data Binding

Last week I was coding a View that required for me to show two ChekBox controls which were mutually exclusive in the same way that two or more RadioButton controls that belong to the same group would interact.

My problem was that one Boolean property which came from a bit column in the database needed to drive which CheckBox would be checked: “Yes” or “No”.

In this example I attempt to show how to code two mutually exclusive checkboxes while binding to the Boolean property described above:

image

The Name of the Property in the Code Behind file that we are going to bind to is AddInsurance.

Here is the XAML code:

Continue reading “WPF coding mutually exclusive Check Boxes with Data Binding”