Reading Badger Water Meter Data for Home Assistant

If you have Badger water meters with the Orion Endpoint GIF2014W-OSE, this post should help you read the data for use in Home Assistant. Here is what my meters look like. I have separate lines and meters for the house and outdoor, since they get charged at different rates.

The GIF2014W-OSE broadcasts data from the water meter over radio frequency (RF). Monthly or quarterly the township water department drives around neighborhoods reading these RF signals to determine everyone’s water usage. You can read the same data with a software defined radio (SDR). I’m using a RTL-SDR Blog V4 dongle with a 915MHz LoRa Antenna and ferrite beads (to filter noise) on a USB extension cable. It plugs directly in to my Home Assistant server.

If you want to test the SDR on your computer before setting everything up in Home Assistant check out the rtl_433 repo on GitHub.

To get started in HA, make sure you’re running a MQTT broker. I use the recommended Mosquitto broker. Install the MQTT Explorer and rtl_433 (next) apps. Note, the main rtl_433 HA app wasn’t updated yet with the latest version of rtl_433, which is needed for the GIF2014W-OSE, so that’s why I had to use the (next) version. It may be updated by the time you’re reading this.

The configuration for the rtl_433 (next) app is stored in a file. I have mine at /homeassistant/rtl_433/rtl_433.conf and here is how my app configuration looks.

Below is a good start for the config file’s contents. Put in your IP address, user, and password.

sample_rate 1600k
gain 28
hop_interval 22
pulse_detect autolevel
pulse_detect minlevel=-35
report_meta level
report_meta noise
report_meta stats:1
output mqtt://[MQTT_IP],user=[MQTT_USER],pass=[MQTT_PASSWORD],retain=1

protocol 282

frequency 905.3M
frequency 906.1M
frequency 906.9M
frequency 907.7M
frequency 908.5M
frequency 909.3M
frequency 910.1M
frequency 910.9M
frequency 911.7M
frequency 912.5M
frequency 913.3M
frequency 914.1M
frequency 914.9M
frequency 915.7M
frequency 916.5M
frequency 917.3M
frequency 918.1M
frequency 918.9M
frequency 919.7M
frequency 920.5M
frequency 921.3M
frequency 922.1M
frequency 922.9M
frequency 923.7M

The water meter endpoint broadcasts across the range of 904.4 to 924.6Mhz and this is going to hop between the 24 frequencies (taken from a GitHub comment) listed in the config every 22 seconds. You may need to tweak the gain, pulse_detect, and other settings depending on your setup. Use your favorite AI to help. If you these next couple of lines to the config file you can see more of what happening, but I wouldn’t leave these in after everything is working.

verbose 7
output json
output log

You can view the HA app’s logs to see more details. When everything is running, open up MQTT Explorer and look for the rtl_433 topics. Hopefully within an hour or two you’ll see something similar to this.

In this screenshot 40338908 and 40313961 are the ids for my meter endpoints. You may see a bunch of other ids for other meters in your neighborhood. You may have physical tags on the devices with their IDs or you can compare the reading values to what is displayed on the water meter.

Now this data can be brought in to Home Assistant. It’ll take some tinkering and customization to fit it all for your HA install. I’m also writing this over a week after setting everything up, so I don’t remember the order of adding everything, but you should be able to do most of it at once and restart. Make sure to update the name, unique_id, source, and state everywhere to fit your needs. The state_topic‘s need to match what you see in MQTT Explorer, and any other cross references have to match your renames. Only use what applies to your situation. If you only have one meter, remove all the outdoor/sprinkler stuff. I’m scraping the Saginaw Township water rates from their web site, so that stuff is going to be very custom, but gives you an idea of what you can do.

In configuration.yaml:

mqtt:
  binary_sensor:
    - name: "House Water Meter Leak"
      unique_id: "house_water_meter_leak"
      state_topic: "rtl_433/9b13b3f4-rtl433-next/devices/Orion-Endpoint/40313908/leaking"
      payload_on: "1"
      payload_off: "0"
      device_class: moisture
    - name: "Outdoor Water Meter Leak"
      unique_id: "outdoor_water_meter_leak"
      state_topic: "rtl_433/9b13b3f4-rtl433-next/devices/Orion-Endpoint/40313961/leaking"
      payload_on: "1"
      payload_off: "0"
      device_class: moisture
  sensor:
    - name: "House - Water Meter"
      unique_id: "house_water_meter"
      state_topic: "rtl_433/9b13b3f4-rtl433-next/devices/Orion-Endpoint/40313908/reading"
      unit_of_measurement: "gal"
      device_class: water
      state_class: total_increasing
      icon: mdi:water-pump
      value_template: "{{ value | float(0) / 10 }}"
    - name: "House - Water Meter Daily Snap"
      unique_id: "house_water_meter_daily_snap"
      state_topic: "rtl_433/9b13b3f4-rtl433-next/devices/Orion-Endpoint/40313908/daily_reading"
      device_class: water
      state_class: total
      unit_of_measurement: "gal"
      entity_category: diagnostic
      icon: mdi:history
      value_template: "{{ value | float(0) / 10 }}"
    - name: "House - Water Meter - Freq 1"
      unique_id: "house_water_meter_freq1"
      state_topic: "rtl_433/9b13b3f4-rtl433-next/devices/Orion-Endpoint/40313908/freq1"
      value_template: "{{ value | float(0) }}"
      unit_of_measurement: "MHz"
      state_class: measurement
      device_class: frequency
    - name: "House - Water Meter - Freq 2"
      unique_id: "house_water_meter_freq2"
      state_topic: "rtl_433/9b13b3f4-rtl433-next/devices/Orion-Endpoint/40313908/freq2"
      value_template: "{{ value | float(0) }}"
      unit_of_measurement: "MHz"
      state_class: measurement
      device_class: frequency
    - name: "Outdoor - Water Meter"
      unique_id: "water_meter_outdoor"
      state_topic: "rtl_433/9b13b3f4-rtl433-next/devices/Orion-Endpoint/40313961/reading"
      unit_of_measurement: "gal"
      device_class: water
      state_class: total_increasing
      icon: mdi:water-pump
      value_template: "{{ value | float(0) / 10 }}"
    - name: "Outdoor - Water Meter Daily Snap"
      unique_id: "outdoor_water_meter_daily_snap"
      state_topic: "rtl_433/9b13b3f4-rtl433-next/devices/Orion-Endpoint/40313961/daily_reading"
      device_class: water
      state_class: total
      unit_of_measurement: "gal"
      entity_category: diagnostic
      icon: mdi:history
      value_template: "{{ value | float(0) / 10 }}"
    - name: "Outdoor - Water Meter - Freq 1"
      unique_id: "outdoor_water_meter_freq1"
      state_topic: "rtl_433/9b13b3f4-rtl433-next/devices/Orion-Endpoint/40313961/freq1"
      value_template: "{{ value | float(0) }}"
      unit_of_measurement: "MHz"
      state_class: measurement
      device_class: frequency
    - name: "Outdoor - Water Meter - Freq 2"
      unique_id: "outdoor_water_meter_freq2"
      state_topic: "rtl_433/9b13b3f4-rtl433-next/devices/Orion-Endpoint/40313961/freq2"
      value_template: "{{ value | float(0) }}"
      unit_of_measurement: "MHz"
      state_class: measurement
      device_class: frequency

scrape:
  - resource: https://saginawtownship.org/departments/public_services/water_distribution.php
    scan_interval: 86400 
    sensor:
      - name: "Saginaw House Water Rate Raw"
        select: "article ul li"
        index: 2
        value_template: >
          {{ value | regex_findall_index('Combined:\s*\$?\s*(\d+\.\d+)', ignorecase=True) }}
      - name: "Saginaw Outdoor Water Rate Raw"
        select: "article ul li"
        index: 2
        value_template: >
          {{ value | regex_findall_index('\(Sprinkler Meter\)\s*\$?\s*(\d+\.\d+)', ignorecase=True) }}

utility_meter:
  house_daily_water:
    name: "House Daily Water"
    unique_id: house_daily_water
    source: sensor.house_water_meter
    cycle: daily
    always_available: true
  outdoor_daily_water:
    name: "Outdoor Daily Water"
    unique_id: outdoor_daily_water
    source: sensor.water_meter_outdoor
    cycle: daily
    always_available: true

In templates.yaml:

- binary_sensor:
  - name: "Outdoor Water Flowing Hourly"
    unique_id: outdoor_water_flowing_hourly
    device_class: moving
    state: >
      {{ states('sensor.outdoor_water_hourly_change') | float(0) > 0 }}
  - name: "House Water Flowing Hourly"
    unique_id: house_water_flowing_hourly
    device_class: moving
    state: >
      {{ states('sensor.house_water_hourly_change') | float(0) > 0 }}
  - name: "Sprinklers Watering"
    unique_id: sprinklers_watering
    device_class: running
    state: >
      {{ is_state('binary_sensor.sprinkler_zone_1_watering', 'on')
         or is_state('binary_sensor.sprinkler_zone_2_watering', 'on')
         or is_state('binary_sensor.sprinkler_zone_3_watering', 'on')
         or is_state('binary_sensor.sprinkler_zone_4_watering', 'on')
         or is_state('binary_sensor.sprinkler_zone_5_watering', 'on')
         or is_state('binary_sensor.sprinkler_zone_6_watering', 'on') }}
  - name: "Outdoor Water Leak Persistent"
    unique_id: outdoor_water_leak_persistent
    device_class: problem
    delay_on: "02:00:00"
    state: >
      {% set water_usage = states('sensor.outdoor_water_hourly_change') | float(0) > 0 %}
      {% set sprinklers_active = states('sensor.sprinklers_active_last_hour') | float(0) > 0 %}

      {{ water_usage and not sprinklers_active }}
  - name: "House Water Nightly Leak Possible"
    unique_id: house_water_nightly_leak_possible
    device_class: problem
    state: >
    
      {% if now().hour == 6 and now().minute == 0 %}
        {# If water usage increased 7/9 hours from 9p-6a #}
        {# (allowing for minor signal lag and missed reads) #}
        {{ states('sensor.house_water_flowing_9_hours') | float(0) > 6.8 }}
      {% else %}
        {{ states('binary_sensor.house_water_nightly_leak_possible') }}
      {% endif %}

In automations.yaml:

- id: '1770044944973'
  alias: Notify - Water Meter Leak Detected
  description: ''
  triggers:
  - trigger: state
    entity_id:
    - binary_sensor.house_water_meter_leak
    - binary_sensor.outdoor_water_meter_leak
    from:
    - 'off'
    to:
    - 'on'
  actions:
  - action: notify.mobile_app_nickphone
    metadata: {}
    data:
      title: "\U0001F6B0 Water Leak Flag Detected!"
      message: The internal leak flag for {{ trigger.to_state.name }} has been triggered.            This
        usually indicates continuous flow for the last 24 hours.
      data:
        priority: high
        ttl: 0
- id: '1770082584926'
  alias: Notify - Outdoor Water Leak
  description: Alerts family when unexplained water flow persists for 2 hours
  triggers:
  - entity_id: binary_sensor.outdoor_water_leak_persistent
    from: 'off'
    to: 'on'
    trigger: state
  conditions: []
  actions:
  - action: notify.mobile_app_nickphone
    metadata: {}
    data:
      data:
        priority: high
        ttl: 0
        tag: outdoor-leak-alert
        color: '#ff0000'
      title: "\U0001F6B0 Outdoor Water Leak Detected"
      message: 'Unexplained water flow has been detected for over 2 hours. Current
        hourly rate: {{ states(''sensor.outdoor_water_hourly_change'') }} gal.'
- id: '1770084282355'
  alias: Notify - House Water Leak Possible
  description: Water meter usage increased every hour from 9p-6a
  triggers:
  - at: 07:01:00
    trigger: time
  conditions:
  - condition: state
    entity_id: binary_sensor.house_water_nightly_leak_possible
    state: 'on'
  actions:
  - data:
      title: "\U0001F3E0 House Water Alert"
      message: Potential water leak detected! Water usage increased every hour from
        9 PM to 6 AM.
      data:
        priority: high
        ttl: 0
        tag: house-leak-alert
        color: '#ffa500'
    action: notify.mobile_app_nickphone
- id: '1770485349188'
  alias: Count House Water Meter Frequency Updates
  triggers:
  - entity_id: sensor.house_water_meter_freq_1
    trigger: state
  actions:
  - target:
      entity_id: input_number.house_water_meter_freq1_updates_per_hour
    data:
      value: '{{ states(''input_number.house_water_meter_freq1_updates_per_hour'')
        | float(0) + 1 }}'
    action: input_number.set_value
- id: '1770485394121'
  alias: Count Outdoor Water Meter Frequency Updates
  triggers:
  - entity_id: sensor.outdoor_water_meter_freq_1
    trigger: state
  actions:
  - target:
      entity_id: input_number.outdoor_water_meter_freq1_updates_per_hour
    data:
      value: '{{ states(''input_number.outdoor_water_meter_freq1_updates_per_hour'')
        | float(0) + 1 }}'
    action: input_number.set_value
- id: '1770485452657'
  alias: Reset Water Meter Freq Hourly
  description: ''
  triggers:
  - hours: /1
    trigger: time_pattern
  actions:
  - action: input_number.set_value
    metadata: {}
    target:
      entity_id:
      - input_number.house_water_meter_freq1_updates_per_hour
      - input_number.outdoor_water_meter_freq1_updates_per_hour
    data:
      value: 0
- id: '1770038217308'
  alias: Notify - Saginaw Water Rate Changed
  description: ''
  triggers:
  - entity_id:
    - sensor.saginaw_house_water_rate
    - sensor.saginaw_outdoor_water_rate
    id: rate_changed
    trigger: state
    alias: Saginaw Water Rate Changes
  - entity_id:
    - sensor.saginaw_house_water_rate_raw
    - sensor.saginaw_outdoor_water_rate_raw
    to: unavailable
    for:
      seconds: 30
    id: scrape_failed
    trigger: state
    alias: Saginaw Water Rate Raw Scrape Changes
  actions:
  - choose:
    - conditions:
      - condition: trigger
        id: rate_changed
      - condition: template
        value_template: "{{ trigger.from_state.state not in ['unknown', 'unavailable']
          and \n  trigger.to_state.state not in ['unknown', 'unavailable'] }}\n"
      sequence:
      - data:
          title: "\U0001F4B0 Water Rate Change"
          message: 'Rate for {{ trigger.to_state.name }} has changed! Old Value: ${{
            trigger.from_state.state }} New Value: ${{ trigger.to_state.state }}'
          data:
            priority: high
            ttl: 0
        action: notify.mobile_app_nickphone
    - conditions:
      - condition: trigger
        id: scrape_failed
      sequence:
      - data:
          title: '⚠️ Scrape Error: Saginaw Water'
          message: 'The scrape for {{ trigger.to_state.name }} failed or returned
            non-numeric data.  Stable value of ${{ states(trigger.entity_id.replace(''_raw'',
            '''')) }} is being maintained. Check: https://saginawtownship.org/departments/public_services/water_distribution.php'
          data:
            priority: high
            ttl: 0
        action: notify.mobile_app_nickphone

In Devices -> Helpers there are a bunch, but some come from templates above and others when you add the water data to your Energy dashboard (after a reboot and data starts coming in). Here’s my list of helpers:

Some key findings when I started looking at the data. My meters are broadcasting many times per minute, but the gallons used reading only changes at 11 minutes after every hour. They do this to save the endpoint battery I guess. So no realtime data, but hourly is better than nothing.

In the data, there is a leaking flag. From what I’ve read this flag only gets turned on if the usage increases for 24 hours straight. Not great for leak detection, but would have been useful last summer when something busted on a sprinkler line and I didn’t find out for a week or so. I have leak notifications based on these flags, but my custom leak notifications should trigger sooner. If the sprinklers have been off and the outdoor usage increases two hours in a row, I’ll get an alert. If the house usage have been increasing all through the overnight I’ll get an alert in the morning.

Once everything is setup, let it run. After several days, check out the freq1 sensor data, which should look similar to these graphs.

Your meters might be different, but mine hop between three frequencies at a time. There’s a low, medium, and high. Every 8 hours (3:11am, 11:11am, and 7:11pm), one of the frequencies increases by 400MHz, so over the course of a day they all increase. Then one day they all peaked and reset to the lower end of a frequency band.

From all this data I knew:

  • Low Band: 904.8 – 910.8 MHz with changes at 7:11 pm
  • Med Band: 911.2 – 917.2 MHz with changes at 3:11 am
  • High Band: 917.6 – 923.6 MHz with changes at 11:11 am

I also tracked how many times per hour I caught data from each meter.

Not bad, but some hours I’d only get one or two data packets for a meter. Technically enough, but there was a risk of missing data. Since I knew the pattern I felt I could do smarter frequency hopping with my SDR to listen for data and then capture a lot more. It worked!

I was getting a lot more reads and rarely less than 10 in any hour. In order to do this I updated the rtl_433.conf file to replace the 24 frequencies with three bands.

# Low band - shifts at 7:11 PM ET (channels 904.8 - 910.8 MHz)
frequency 904.4M
#frequency 904.8M
frequency 905.2M
#frequency 905.6M
#frequency 906.0M
#frequency 906.4M
#frequency 906.8M
#frequency 907.2M
#frequency 907.6M
#frequency 908.0M
#frequency 908.4M
#frequency 908.8M
#frequency 909.2M
#frequency 909.6M
#frequency 910.0M
#frequency 910.4M
#frequency 910.8M
#frequency 911.2M

# Mid band - shifts at 3:11 AM ET (channels 911.2 - 917.2 MHz)
frequency 910.8M
#frequency 911.2M
frequency 911.6M
#frequency 912.0M
#frequency 912.4M
#frequency 912.8M
#frequency 913.2M
#frequency 913.6M
#frequency 914.0M
#frequency 914.4M
#frequency 914.8M
#frequency 915.2M
#frequency 915.6M
#frequency 916.0M
#frequency 916.4M
#frequency 916.8M
#frequency 917.2M
#frequency 917.6M

# High band - shifts at 11:11 AM ET (channels 917.6 - 923.6 MHz)
frequency 917.2M
#frequency 917.6M
frequency 918.0M
#frequency 918.4M
#frequency 918.8M
#frequency 919.2M
#frequency 919.6M
#frequency 920.0M
#frequency 920.4M
#frequency 920.8M
#frequency 921.2M
#frequency 921.6M
#frequency 922.0M
#frequency 922.4M
#frequency 922.8M
#frequency 923.2M
#frequency 923.6M
#frequency 924.0M

# ^ keep blank line

The two uncommented frequencies in each band are the ones on either side of the frequency currently used by the meters. I added a scripts folder and a new update_rtl433_channels.sh file in there.

#!/bin/bash
# update_rtl433_channels.sh
#
# Advances one band's straddled frequency pair in the rtl_433 config.
# Two frequencies are active, 0.8 MHz apart, straddling the actual
# channel by 0.4 MHz on each side.
#
# Each shift: comment both active lines, uncomment the line
# immediately after each (the next two in the gap positions).
# At wrap: jump back to the first and third positions.
#
# Usage: update_rtl433_channels.sh <low|mid|high> [config_path]

BAND="$1"
CONFIG_PATH="${2:-/config/rtl_433/rtl_433.conf}"

if [ -z "$BAND" ]; then
    echo "Usage: $0 <low|mid|high> [config_path]"
    exit 1
fi

if [ ! -f "$CONFIG_PATH" ]; then
    echo "Error: Config file not found: $CONFIG_PATH"
    exit 1
fi

# Determine the section header
case "$BAND" in
    low)  SECTION="# Low band -" ;;
    mid)  SECTION="# Mid band -" ;;
    high) SECTION="# High band -" ;;
    *)    echo "Error: band must be low, mid, or high"; exit 1 ;;
esac

# Find start line of this section
SECTION_START=$(grep -n "$SECTION" "$CONFIG_PATH" | head -1 | cut -d: -f1)
if [ -z "$SECTION_START" ]; then
    echo "Error: Could not find section '$SECTION' in config"
    exit 1
fi

# Find end line: next section header or end of file
NEXT_SECTION=$(tail -n +$((SECTION_START + 1)) "$CONFIG_PATH" | grep -n "^# .* band -" | head -1 | cut -d: -f1)
if [ -z "$NEXT_SECTION" ]; then
    SECTION_END=$(wc -l < "$CONFIG_PATH")
else
    SECTION_END=$((SECTION_START + NEXT_SECTION - 1))
fi

echo "Band: $BAND (lines $SECTION_START-$SECTION_END)"

# Get absolute line numbers of all active (uncommented) frequency lines
ACTIVE_ABS=()
for LINE_NUM in $(seq "$SECTION_START" "$SECTION_END"); do
    if sed -n "${LINE_NUM}p" "$CONFIG_PATH" | grep -q "^frequency "; then
        ACTIVE_ABS+=("$LINE_NUM")
    fi
done

if [ "${#ACTIVE_ABS[@]}" -ne 2 ]; then
    echo "Error: Expected 2 active frequencies, found ${#ACTIVE_ABS[@]}"
    exit 1
fi

FIRST_ABS=${ACTIVE_ABS[0]}
SECOND_ABS=${ACTIVE_ABS[1]}

echo "Active:"
echo "  Line $FIRST_ABS: $(sed -n "${FIRST_ABS}p" "$CONFIG_PATH")"
echo "  Line $SECOND_ABS: $(sed -n "${SECOND_ABS}p" "$CONFIG_PATH")"

# Find the line immediately after each active line
AFTER_FIRST=$((FIRST_ABS + 1))
AFTER_SECOND=$((SECOND_ABS + 1))

# Check if both "after" lines exist and are commented frequencies
AFTER_FIRST_OK=""
AFTER_SECOND_OK=""

if [ "$AFTER_FIRST" -le "$SECTION_END" ]; then
    if sed -n "${AFTER_FIRST}p" "$CONFIG_PATH" | grep -q "^#frequency "; then
        AFTER_FIRST_OK=1
    fi
fi

if [ "$AFTER_SECOND" -le "$SECTION_END" ]; then
    if sed -n "${AFTER_SECOND}p" "$CONFIG_PATH" | grep -q "^#frequency "; then
        AFTER_SECOND_OK=1
    fi
fi

if [ -z "$AFTER_FIRST_OK" ] || [ -z "$AFTER_SECOND_OK" ]; then
    # At end of section — wrap to first and third positions
    echo "End of section, wrapping"

    # Comment out both active lines
    sed -i "${FIRST_ABS}s/^frequency /#frequency /" "$CONFIG_PATH"
    sed -i "${SECOND_ABS}s/^frequency /#frequency /" "$CONFIG_PATH"

    # Find first and third commented frequency lines (positions 0 and 2)
    WRAP_LINES=()
    for LINE_NUM in $(seq "$SECTION_START" "$SECTION_END"); do
        if sed -n "${LINE_NUM}p" "$CONFIG_PATH" | grep -q "^#frequency "; then
            WRAP_LINES+=("$LINE_NUM")
            if [ "${#WRAP_LINES[@]}" -eq 3 ]; then
                break
            fi
        fi
    done

    sed -i "${WRAP_LINES[0]}s/^#frequency /frequency /" "$CONFIG_PATH"
    sed -i "${WRAP_LINES[2]}s/^#frequency /frequency /" "$CONFIG_PATH"
else
    # Normal advance: comment both active, uncomment the line after each
    echo "Advancing: commenting $FIRST_ABS,$SECOND_ABS, uncommenting $AFTER_FIRST,$AFTER_SECOND"

    sed -i "${FIRST_ABS}s/^frequency /#frequency /" "$CONFIG_PATH"
    sed -i "${SECOND_ABS}s/^frequency /#frequency /" "$CONFIG_PATH"
    sed -i "${AFTER_FIRST}s/^#frequency /frequency /" "$CONFIG_PATH"
    sed -i "${AFTER_SECOND}s/^#frequency /frequency /" "$CONFIG_PATH"
fi

echo ""
echo "Active frequencies:"
grep "^frequency " "$CONFIG_PATH"

This file needs a permissions change. Install the Terminal & SSH app in HA, start it, open it, and type:
chmod +x /config/config/update_rtl433_channels.sh.

In configuration.yaml:

shell_command:
  rtl433_shift_low: 'bash /config/scripts/update_rtl433_channels.sh low /config/rtl_433/rtl_433.conf'
  rtl433_shift_mid: 'bash /config/scripts/update_rtl433_channels.sh mid /config/rtl_433/rtl_433.conf'
  rtl433_shift_high: 'bash /config/scripts/update_rtl433_channels.sh high /config/rtl_433/rtl_433.conf'

In automations.yaml:

- id: '1770813439694'
  alias: RTL 433 - Shift Low Band Frequencies
  description: Advances low band frequencies at 7:11 PM ET daily
  triggers:
  - trigger: time
    at: '19:11:00'
  actions:
  - action: shell_command.rtl433_shift_low
  - delay:
      seconds: 5
  - action: hassio.addon_restart
    data:
      addon: 9b13b3f4_rtl433-next
  mode: single
- id: '1770813477228'
  alias: RTL 433 - Shift Mid Band Frequencies
  description: Advances mid band frequencies at 3:11 AM ET daily
  triggers:
  - trigger: time
    at: 03:11:00
  actions:
  - action: shell_command.rtl433_shift_mid
  - delay:
      seconds: 5
  - action: hassio.addon_restart
    data:
      addon: 9b13b3f4_rtl433-next
  mode: single
- id: '1770813511146'
  alias: RTL 433 - Shift High Band Frequencies
  description: Advances high band frequencies at 11:11 AM ET daily
  triggers:
  - trigger: time
    at: '11:11:00'
  actions:
  - action: shell_command.rtl433_shift_high
  - delay:
      seconds: 5
  - action: hassio.addon_restart
    data:
      addon: 9b13b3f4_rtl433-next
  mode: single

Make sure to uncomment the correct frequencies in each band, update the automation trigger times, and make sure the slug for the rtl433-next app is correct. Each time an automation runs the active frequencies are updated for the associated band. Since they should be on both sides of the frequency used by the water meter both can read the RF broadcasts. When it gets to the end of the band’s frequency list, it shifts up to the top of the list.

A lot of this is dependent on your water meters and situation, but hopefully it gives you enough information to make it work.

Home Ethernet and Wi-Fi

A big part of the planning for our house included Ethernet wiring because I want to hardwire every device I can, saving the Wi-Fi for devices that require it. It’s much easier and cheaper to get everything wired during the build, instead of adding later. I went through several iterations of the plan and in the end I had the electricians do 42 runs of Cat6:

  • 4 jacks in the office
  • 2 jacks in the office closet
  • 2 jacks in the pocket office
  • 2 jacks in the guest bedroom
  • 4 jacks behind the TV
  • 2 jacks in the living room
  • 2 jacks in the dining room
  • 2 jacks in the pantry
  • 2 jacks in the laundry room
  • 4 jacks in the walk in closet
  • 6 jacks in the master bedroom
  • 10 wires to 5 exterior camera locations (1 extra at each location)

They run it all up through the ceiling. I’m guessing that is to keep it away from most of the electrical. Here’s the master bedroom nightstand wiring as an example.

Then all of the cables comes over and down a wall between the laundry room and garage.

Ending at a single location in the basement.

We built a wall (part 1 & 2) and since we moved in back in August I’d had the cable modem and old eero router sitting on top of the network rack filled with new equipment.

Last December I added some supports to the rack and couple of weeks ago I built a cart. Then I moved the modem and router inside.

Throughout the house, I put port covers on the unused jacks. Here’s how a wall plate looks with one port open and one covered. The covers will help protect the internals and keep dust out.

What did I buy for my network? A LOT! Here’s all of the stuff for the rack, cables, and tools.

When it came to the actual networking equipment I took a good look at the stuff from Ubiquiti/UniFi. It’s top of the line, which is reflected by the price tag. I decided to go with TP-Link instead, saving a lot of money.

Before I started wiring everything through the rack, I cleaned up the cables.

The electricians had done all of the wall jacks throughout the house with the newer T-568B wiring standard, so I followed suit. I learned how to wire the keystone jacks and insert them in to the patch panels.

I’d never done anything like this and it was so much fun. By the end, I was pretty quick with each keystone jack. I highly recommend the Everest 45° ones and the tool for it. The basement needed some Ethernet ports for the golf sim, so I ran four new cables from the rack. I installed a couple of electrical boxes in the ceiling and wired jacks there.

I also needed a custom length Ethernet cable to run from the ceiling jack down to the gaming PC. I’d tried putting RJ45 jacks on the end of an Ethernet cable or two a long time ago and remember it being almost impossible. After watching a quick YouTube video (even though I don’t have pass through connectors), I was able to put both ends on my new cable without a problem and it passed the test.

Then I was able to use patch cables to connect ports on the patch panel to the switch as well as hook up the cable modem, Pi-hole Raspberry Pi, and TP-Link equipment. There’s also a Dell Micro in there, which I’ll cover in a later post about smart home.

When I tried to access the Omada controller I couldn’t bring up the web interface with Chrome on my Mac. After trying a bunch of stuff I checked from my iPhone and it worked. I tried Safari on my Mac which also worked. It turned out I had always prevented Chrome from accessing my local network. I flipped the switch in System Settings and the interface loaded.

At another point I accidentally disabled all of the ports on the switch. The UI splits the switch ports across three pages, and on page two I had clicked the button to select all, unselected a port, and disabled the nine other ports. I quickly realized it disabled 27 of the 28 ports. I was so pissed! Every other UI I’ve ever used will only select the items in view when you click the Select All button, but not the Omada Controller software. In order to get back in I had to access the switch via the USB console, reset the switch to factory settings, and start over.

I’m running four VLANs, named Default, Guest, IoT, and nIoT. IoT is for my Internet of Things (smart home) devices that need to access the Internet and the “n” in nIoT stands for “not” since I don’t want them to access the Internet. The Default and IoT networks are set to get their DNS from my Pi-hole server, which blocks ads and other malicious domains.

Each VLAN has a matching wireless network. The Guest Wi-Fi is set as a guest network, which automatically prevents any device from accessing another. The wireless networks for IoT and nIoT are only set to use the 2.4 GHz band since most of the devices will not work on 5 GHz.

I added mDNS rules for Printers and AirPlay devices from the IoT network to the Default network.

It took me awhile to figure out the ACL rules. I have two for the Gateway. The first prevents any outside IP from accessing my network management page and the second prevents the nIoT network from accessing the Internet.

I ended up with six rules for the switch, since the default behavior of the Omada stuff is to permit everything. With my Pi-hole server on the IoT network I had to allow it’s IP to access anything on the Default network (this should probably be limited to specific ports). I had to allow some ports from the camera IPs to access the Default network and I had to allow some ports from my Home Assistant server to access the Default network. I may find out I need to adjust those ACLs, but more on those smart home aspects in a future post. Then the IoT and nIoT networks are denied from accessing Default and a bi-directional rule prevents the Guest network from accessing any other network.

Seems to be running pretty well. I have some smart home stuff on the network, but haven’t connected any of the light switches yet and have a lot of Home Assistant configuration to do. Originally I didn’t have an access point in the basement, but after a few days realized it was necessary and added one. Here’s a view of the network topology, automatically generated by the Omada controller.

If you upload a floor plan and place walls, the software can even run a wireless coverage simulation. The house has great signal and the yard should get good connections as well.

Power over Ethernet is pretty sweet. It’s so nice not needing power cables for the 10 devices with PoE support.

Time to finish setting up my server and smart home devices. Watch for an upcoming post with all of the details.

% Better/Worse

This showed up in my Facebook memories this morning and I quickly shared it.

tiny-gainz

Then I thought about it for a minute and the scale on the chart seemed out of whack, so I deleted the post. I opened up a Google spreadsheet and started messing with numbers. Here’s what a real chart looks like if you improve by 1% each day.

1-percent-changes

What does this really show though? If the starting number 1 represents your current ability in some skill, the end result is your ability in that skill. So if you improved by 1% each day, at the end of a year your skill level would be over 37x what it currently is. Conversely if you got 1% worse each day, at the end of a year you’d be left with about 2.5% of your original ability. I can’t think of any skill where either that much of an improvement or decline is possible by any stretch of the imagination.

What about 0.1% changes though?

tenth-of-percent-changes

If you got 0.1% better each day for a year, your skill level would improve by 44% and if you got 0.1% worse each day you’d be left with just under 70% of your ability. Now we’re getting somewhere realistic!

It’s still hard to grasp what that means though, with 1 representing some ability or skill level. To put this in perspective, I’ll use the time it takes to run a mile. Starting with a 10 minute mile on day one makes it easy to understand.

If you run 1% faster each day, you’d have to run a 15.5 second mile at the end of the year. Good luck!

If you run 0.1% faster each day, you’d be running a mile in 6:56 at the end of the year. That’s seems possible doesn’t it?

Historical Currency Exchange Rates

Usually when I need to get a bunch of past exchange rates I use the GOOGLEFINANCE function in Google Spreadsheets. Something like this…

=GOOGLEFINANCE("EUR", "price", DATE(2016,1,1), TODAY(), "DAILY")

It’s quick and easy, but once in a while you’ll run into a currency where this doesn’t return enough precision, compared to the value you get when using Google’s currency converter. Even worse, today it was giving me a bunch of data that was quite different from what Google Finance showed for the current and historical data.

I found a site run by the University of British Columbia that’ll give you whatever data you need. It’s not pretty but it does the job. Those Canadians are always so generous!

Performancing Metrics

Performancing came out with a free public beta of a blog tracking service earlier this week, called Performancing Metrics. I haven’t used it a very much yet, but it looks very promising. Most statistics services and packages are bloated with useless data. PM gives bloggers access to the data they’ll need most often and it works great. The site responds quickly and stats are updated every hour. Best of all…you can track multiple blogs from one account!

Backup

I just read a very interesting article by Vince Barnes of HTML Goodies.

Three Golden Rules

Intriguing title, don’t you think? We’ll get to them in just a second. First, let’s take a quick look at the “coming to life” of your website.

Imagine if you will, all the thought that goes into a website; then the work involved in it’s actual creation; the care with which its various elements are interconnected; and the pride with which it is placed onto a web server and published for the world to see.

Next, a little time goes by and the site evolves with a tweak here, add a page there, put a database link in this, and so on. Pretty soon the site has grown a lot and represents its developer’s blood, sweat and tears. Then the server crashes and the call comes in from hosting company to say “sorry, you’ll have to upload your pages again.” Pages? PAGES? WHAT PAGES? The horror dawns on you that your only copy is that original set that you first created. All that extra work was done after that upload and was added piece by piece to the live site. Only the live site had it all. And that database of contact information you’ve been collecting — it was up there too!

Now to those golden rules. They apply to everything to do with computers, but we’re especially interested in how they apply to website creation and maintenance. I’m sure you’ve guessed the first part by now. That’s right — Backup!

Rule number one is backup your stuff! When you make a copy, however, things can go wrong with the copy process. It’s a good idea to make a copy of your existing backup before you start to copy over it — just in case! Now you have a one generation old copy and a current copy.

Then there’s Murphy’s Law. “If it can go wrong it will. If it can’t go wrong, it’ll go wrong quicker.” (If that’s not actually Murphy’s Law, I’m sure he’d be pretty proud of it anyway!) Here’s the scene (it’s based on the last one): as your hanging up the phone after the call from the hosting company a knowing smile stretches itself across your face; “I have those two copies in the other room – let me get one and send it up,” you think to yourself. As you do, and as if in direct response to your smirk, a bolt of lightning comes out of the blue, smashes its way through your roof, through the back room, through your computer and melts your CDs and floppies as it goes.

Oops! (Thank goodness it missed the cat – this is, after all, a family style newsletter!)

Yes, that’s right — you should have made another copy and kept it at work or in your safe deposit box. An off-site copy is another very reasonable backup. Of course, its possible that the call comes from the hosting company, a bolt takes out your PC and a flash flood washes away the bank. If this happens to you, you might want to examine your life a little – the universe seems to be exceptionally mad at you.

So, more correctly stated, rule one would be “backup your backups.” That would leave rule two as “backup your stuff” and rule three as “backup your stuff again and keep the backup off-site.” The short form of the three golden rules is:

Backup backup; backup; and backup again.

Say that to yourself a few times. Now ask yourself “did I just say that, or have I actually done it?”

-Vince Barnes

Working for a Support Center, I see people losing data/files all the time because they didn’t have a backup copy. I have no sympathy for these people. I know that when I have something important, I always keep several copies of it. I’ll keep a copy at home, at work, on a CD, in my email…anywhere I can think of. Maybe someday people will learn their lesson.