Feb. 29, 2020, 8:25 p.m.

Pi-Hole HA

Or my efforts to give my family an SLA.

At work I'm constantly dealing with servers that aren't redundant and so need buy-in and advance notice whenever we need to bring them down for maintenance. I started thinking about this for the home front after I installed my first Raspberry Pi running Pi-Hole. If you aren't aware, Pi-Hole acts as a middle man for IP address requests to locations on the world-wide-web. To do this your network needs to point to your Pi-Hole as the server to ask for all DNS requests your device doesn't already know about. DNS requests happen A LOT so all networks should have multiple DNS servers that they can ask for this information. This prevents communication failures and slowdowns from impacting the always important activity of lurking r/ProgrammerHumor. On a more serious note, this also allows for the devices to be taken completely off-line to do periodic backups.

Setting up a Pi-Hole is actually really easy. I followed the official install instructions which is run in a single command. The most challenging part of the setup is getting everything else configured correctly. The next task is to configure your DHCP provider to point to the Pi-Hole for DNS. I recently upgraded my home network to Unifi equipment which allows for this kind of advanced configuration. The Comcast router that we had prior to that wouldn't allow it so running a Pi-Hole was not an option.

In the Unifi Controller these DNS settings are called "DHCP Name Server" which I guess is technically correct but I spent way too long time looking for "DNS server" settings. Unifi allows for setting up to 4 different IP addresses for DHCP name servers. Initially when I setup a single Pi-Hole I used the address for my Pi-Hole and then Google's DNS server @ This would allow for local devices to always have an active DNS server but queries to would by-pass the Pi-Hole and could let ads slip through.

It's tempting to think of these multiple DNS servers as "primary" and "secondary" where the secondary is the fallback in-case the primary isn't available. In fact the DNS spec doesn't define how devices use multiple DNS server addresses so it's up to the device manufacturer to set that behavior. All of the devices that I have mainly use the first DHCP name server so I never really noticed ads getting through. Regardless, DNS for my network wasn't going through the pi's at 100% which was a major motivation to setup the second one.

My next task was to add hostnames for all the devices on my network with static IP addresses. At this time I've got 3 pi's running, a router, a switch, and a couple of wireless access points. Defining local DNS names isn't supported out of the box with pi-hole so there's some manual configuration that needs to be done. I found HOWTO: Using pi-hole as LAN DNS server on pi-hole.net that shows the steps to accomplish this. It's an easy task and IMO a great improvement for homelabs.

The last task was to setup a system for syncing the configuration between the two Pi-Holes. This includes the white lists, black lists, and most importantly for me, the lan list which is where my hostnames are defined. Initially I found a script that was fairly simple which used rsync to transfer the files to the second pi-hole and then restart the pi-hole services if any were updated. It was written in bash and I was tempted to re-write with Python to make it my own. While searching for a source on github I cam across another version of the script which was named, Pi-Hole Gemini (instructions) (script). This version was a vast improvement and I definitely didn't have anything to gain by trying to do it myself so I installed it as is. The script still uses rsync to transfer the data but it also has logging, better IP address & port customization, and better handling of updates on the remote pi-hole.

I'm really really happy with the dual Pi-Hole setup. All of the DNS queries coming out of my network are being filtered for advertising which is a benefit the whole family can enjoy! Plus they cache DNS requests so we get "better performance" and I get to define hostnames for all my Pi projects :D.


March 13, 2019, 8:02 p.m.

AccuTerm Client for Sublime Text


AccuTerm client is a plugin for Sublime Text allows you to connect to a MultiValue server using AccuTerm. This plugin allows for

source code editing and compiling on remote MV servers as well as executing commands and using the native data conversion processing codes (OCONV/ICONV).


Standard Features

These features will work with all MV DBMS that support Accuterm.

  • Download & upload files

  • Compile source code

  • Lock/Unlock items on the MultiValue server

  • Iconv/Oconv from Sublime

  • Run currently open file

  • Execute commands on the MV Server and display output in Sublime

  • Global case change while preserving case in comments & strings

Extended Features

These features require DBMS specific configuration to run. D3, QM, and jBASE are configured automatically. Additional DBMS can be setup manually (see the Settings section below).

  • Prev/Next compile error

  • Browse command stack

  • Browse files on MV server (jBASE Windows not supported)


  • Sublime Text 3

  • PyWin32 Sublime Package

  • Windows Operating System

  • AccuTerm terminal emulator running the FTSERVER program


Using Sublime Package Manager

  1. Package Control: Install

  2. AccuTermClient

Using Github

  1. cd %appdata%\Sublime Text 3\Packages

  2. git clone https://github.com/ianharper/AccuTermClient.git

  3. Install the PyWin32 Sublime package.


This package connects to your MV database using AccuTerm's FTSERVER program. To use, launch AccuTerm and run FTSERVER from TCL. AccuTermClient will connect to the AccuTerm server with no additional configuration.

This package expects that all files on your local machine to be contained in a folder that matches the file on the MV server. Files will be named on your local machine with a ".bp" suffix. When uploaded to the MV server this suffix will be removed.

Example: C:\code\BP\HELLO.WORLD.bp will be uploaded to BP HELLO.WORLD in the account that FTSERVER is running in.


  • Open - Download item from MV server by entering MV file reference. Will lock item on MV server if open_with_readu setting is true.

  • Open (Read Only) - Download item from MV sever without locking by entering MV file reference.

  • Upload - Upload current file to MV server.

  • Compile - Compile Current file on MV server.

  • Release - Release lock of current file on MV server.

  • Release All - Release all locks held by current user on MV server.

  • Unlock - unlock item on MV server by entering MV file reference.

  • Refresh - Update currently open file in Sublime from MV server and lock item on MV server.

  • Check Sync (Current File) - Compare the currently open file to the item on the MV server. If the item on the MV server is different than the local file you will be asked if you want to download the changes from the MV server.

  • List - Browse files on MV server using Sublime's command palate, select item with enter to download.

  • Lock - Lock item on MV server by entering MV file reference.

  • Execute - Run commands on MV server and show output in Sublime (to console, new file, or append to current file).

  • Run - Run the currently open file. If the item is in the MD/VOC then the item name will be used to run (enables running PROC, PARAGRAPH, or MACRO commands).

  • Iconv/Oconv - Convert data using the MV server's iconv/oconv functions.

  • Global Upcase - Convert case of currently open file to uppercase while preserving case in strings and comments.

  • Global Downcase - Convert case of currently open file to lowercase while preserving case in strings and comments.


The settings can be accessed in the Preferences>Package Settings>AccuTermClient>Settings. The settings are in json format. Each top level key-value pair will be explained below. Some settings are specific to the MV DBMS, they will have a second key that specifies the DBMS. This key for your DBMS can be found in ACCUTERM,ACCUTERMCTRL, KMTCFG<51>. These settings can be set for general editing in Sublime or for specific Sublime projects.

  • multivalue_syntaxes List of MV syntaxes. Referenced to determine if a file in Sublime is MultiValue.

  • default_save_location Location to save MV files by default. When editing a file in a Sublime project the project folder will be used instead.

  • remove_file_extensions File extensions to remove when uploading to the MV server.

  • compile_command Command to execute when the Sublime Build command is run.

  • open_with_readu Lock files on MV server when opening.

  • result_line_regex Regular expression used to find the line number of compile errors. See exec Target Options in the Sublime Docs for details.

  • list_files_command Command to list all the files in the account. Used in the AccuTermClient List command. The output must contain only the file name, one per line.

  • list_command This command is run after a file is chosen from the List command. The value is appended to a "SORT (filename) " command to limit the output to only the item names.

  • syntax_file_locations List of MV syntaxes to apply after downloading. The default values come from the MultiValue Basic Sublime package

  • command_history MV file and item for the command stack.

Custom Commands

Custom commands can be easily added from Preferences>Package Settings>AccuTermClient>Custom Commands. When added these commands will be shown in Sublime's command palate. The syntax for these commands follows Sublime's command syntax which is in JSON format (with comments).




    // Name the command

    "caption": "Term - Disable page breaks",

    // Set the Sublime command to run

    "command": "accu_term_execute",

    // Set the command to run on the MV server and where to show the output (console, new, append, or replace).

    "args": { "command": "TERM 150,0", "output_to": "console"}




  • Add support for jBASE windows.

  • Set MV syntax automatically based on DBMS type and file contents (ex. PQ in line 1 should set PROC).

  • Allow file extensions to be set based on DBMS type and file contents (ex. PQ in line 1 should set proc ext.).

Jan. 8, 2018, 9:21 p.m.


Sublime Text syntax highlighting, indentation, and sinppets for MultiValue Basic.


  • MultiValue Syntaxes Supported:

  • D3

  • OpenQM

  • "\" Quotes

  • Auto-Indentation while typing

  • "wED" Color Scheme (at least this is how I've setup colors in wED)

  • Integration with Sublime's Goto Definition for MV Basic line labels

  • Snippets:

  • if-then if-else if-then-else

  • for dcount-for

  • loop-repeat

  • execute-loop-readnext-read-repeat

  • begin case-case-end case

  • open

  • read-readnext


Installation is easy with Sublime's command palate:

Package Control: Install Package

MultiValue BASIC


Pull requests are welcome. For major changes please open an issue to discuss what you would like to change.


  • Add additional MV dialects

  • Enable goto definition for subroutine calls

  • Add uppercase tab completions for snippets

  • Rework syntax definition to suppport meta_scopes for MV blocks (for, if, loop, clauses, etc).