3 Custom Protocol with HA
jimmejames edited this page 2024-03-08 21:42:44 -06:00

Adding your own custom device is easy (YMMV), and extremely satisfying (IMHO). With more simple signals, you maybe able to utilize the native tools to record and listen for particular signals. This isn't meant to be a beginning-to-end tutorial as there's amble documentation available for setting up the prerequisites and the variable definitions. The intent is the quick-and-dirty I wish I had found to quickly get some data from my SDR that I could then tailor for my application.

For example, I wanted to integrate a Wonderful Home D10 doorbell into Home Assistant, but the device was not natively supported by rtl_433 (read: I couldn't select a protocol number in the rtl_433 template), so I created a custom integration.

1: Research your device's frequency. I'd advise you take advantage of public FCC documentation. In my application, the frequency was 433875000 Mhz, so I created a file here: /homeassistant/rtl_433/rtl_Spa.conf.template with the following:

output kv
output mqtt://192.168.1.100:1883,user=<username>,pass=<password>
frequency 433875000
analyze_pulses true

Obviously you need to replace the IP address, username, password, and frequency with the particulars of your configuration and device.

2: Restart rtl_433 by going to Settings -> Add-ons -> rtl_433 -> Restart. Then, navigate to the Log tab and review the date (I extracted the following from a much larger output):

[rtl_Spa] Use a flex decoder with -X 'n=name,m=OOK_PWM,s=172,l=564,r=1800,g=624,t=157,y=0
[rtl_Spa] [01] {33} 14 8d df b9 80 : 00010100 10001101 11011111 10111001 1

3: Re-edit /homeassistant/rtl_433/rtl_Spa.conf.template with the data from your log output's data:

output kv
output mqtt://192.168.82.113:1883,user=<username>,pass=<password>
frequency 433875000

decoder {
    name=Wonderful_Home_Doorbell,
    modulation=OOK_PWM,
    short=156,
    long=548,
    reset=1832,
    gap=652,
    tolerance=157,
    match={33}0x148DDFB980
    unique,
}

Optional
Home Assistant, at that point, could 'see' the device if I told MQTT to 'Listen to a topic', but it wasn't yet an automation. As my device was a simple binary 'button press' or 'button not pressed' signal, I started out trying to look at the data received in MQTT for a match to my expected string (148DDFB980), but found that parsing the JSON data was frustrating as I couldn't be guaranteed any particular row of data would have my string. Read: I couldn't reliably determine when I'd see my target string and I got annoyed with it long before I attempted to show my wife, so it was a definite no-go.
Fortunately, as my device only sent one signal that was repeated multiple times when the button was pressed, I only cared when Home Assistant parsed the data and saw the target signal.

As such, I created a Sensor in a *.yaml file that looked at the the timestamp of the entity for my device. In other words, the rtl_Spa.conf.template looks for a match defined in the template and, when successful, records the time:

mqtt:
  sensor:
     - name: "Spa Doorbell Time"
       state_topic: "rtl_433/+/events/#"
       value_template: "{{ value_json.time }}"

Last, then, I created an automation that watches the timestamps and sends a notice when there's a change (in other words, when someone presses the button). I've baked additional rules into the automation so restarts/reboots do not trigger the automation to send a notice... unfortunately, this doesn't yet always work <- still trying to get the right set of rules in place.

alias: Spa_Doorbell
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.spa_doorbell_time
    id: Doorbell_State_Change_Trigger
condition:
  - condition: and
    conditions:
      - condition: template
        value_template: "{{ states('sensor.spa_doorbell_time') != 'unknown' }}"
      - condition: template
        value_template: "{{ states('sensor.spa_doorbell_time') != 'unavailable' }}"
      - condition: template
        value_template: "{{ trigger.from_state != trigger.to_state}}"
      - condition: template
        value_template: "{{ trigger.to_state != 'unavailable'}}"
      - condition: template
        value_template: "{{ trigger.to_state != 'unknown'}}"
action:
  - service: notify.mobile_app_your_device
    metadata: {}
    data:
      title: Spa Needs Attention
      message: Check Spa
mode: single

Tip from a Pro: If you have trouble with reliability then: round up gap and reset by 10-20% to allow more margin in the timings. Then maybe drop tolerance to accept the widest range of timings.