Introducing ModbusBoard – A Compact Custom Integration for Modbus Sensors

Hi everyone,

I’m excited to share my new custom component, ModbusBoard, designed to simplify handling Modbus sensors in Home Assistant. This integration is built for an easy and compact configuration where all processing templates are defined right under the sensor configuration. Plus, it comes with robust, built-in value processing logic.

You can check out the repository here: ModbusBoard on GitHub.

What Does ModbusBoard Do?

  • All-in-One Configuration:
    Keep your processing templates (calculation, condition, and postprocessing) within each sensor’s configuration. No need for separate processing rules!

  • Built-in Value Processing:
    Automatically applies scaling factors, offsets, rounding, min/max value constraints, and even counter modes (with reset options like hourly, daily, monthly).

  • Compact & Customizable:
    Configure board-level defaults (like factor, offset, etc.) and override them on a per-sensor basis as needed.

How It Works

The integration reads raw Modbus CSV data or sensor states and processes them in several steps:

  1. Undefined Value Check:
    If the raw sensor value is undefined or invalid, a fallback value is returned.

  2. Input Source:

    • If you are using a Modbus CSV input, you must specify both modbus_entity and an index to extract the correct value from the CSV data.
    • Alternatively, if you want to derive the sensor state using a template, you must provide a calculation template. The calculation template overrides the CSV index method.
  3. Ignore Values:
    Skips values listed in the ignore list.

  4. Scaling:
    Applies the defined factor and offset to adjust the raw value.

  5. Constraints:
    Checks for minimum and maximum valid values.

  6. Rounding:
    Rounds the computed value to the specified number of decimal places.

  7. Condition:
    Evaluates an optional condition template. If the condition is not met, the sensor retains its previous value.

  8. Reset:
    If configured, supports counter mode by resetting the value when the specified time period (hourly, daily, monthly) changes.

  9. Postprocessing:
    A final template modifies the sensor value—for example, incrementing a counter by adding the previous processed value to the current value.

Template Variables and Stored Attributes

The integration now uses updated keys for storing and passing sensor state information. These keys are:

Stored Attribute Keys

  • cur_val: Current sensor value.
  • prev_val: Previous sensor value.
  • cur_raw: Current raw sensor value.
  • prev_raw: Previous raw sensor value.
  • prev_proc: Previous processed (postprocessed) value.

Template Variable Names

When evaluating templates for calculation, condition, and postprocess, the following variables are provided:

  • new_val: Candidate new sensor value.
  • cur_val: Current sensor state.
  • prev_val: Previous sensor state.
  • cur_raw: Current raw value.
  • prev_raw: Previous raw value.
  • prev_proc: Previous processed value.

These variables enable you to implement custom logic—such as incrementing a counter based on a rising edge—in your Jinja2 templates.

Example: Counter Sensor Configuration

The following example shows how to configure counter sensors. In this example, a raw rotation count from burner_feeder_signal is used to increment a counter only on a rising edge (i.e., when the previous raw value was 0 and the current raw value is greater than 0). The postprocessing template increments the counter by adding the current processed value (cur_val) to the previous processed counter (prev_proc).

friendly_name: "Basement EBYTE-831-RTU module"
name: e831rtu_basement
sensors:
  burner_feeder_signal:
    friendly_name: "Burner Feeder Signal"
    modbus_entity: sensor.modbus_e831rtu_01_count
    index: 0
    rounding: 0
    precision: 0
    undefined_value: 0
    unit_of_measurement: rotations
    icon: mdi:rotate-right

  burner_feeder_counter_day:
    friendly_name: "Burner Feeder Counter Day"
    # Calculation retrieves the current raw rotations.
    calculation: "{{ states('sensor.burner_feeder_signal')|int(0) }}"
    # Condition: Increment only on a rising edge.
    condition: "{{ (prev_raw|int(0)) == 0 and (cur_raw|int(0)) > 0 }}"
    reset: daily
    # Postprocessing: Add the previous processed counter to the current calculated value.
    postprocess: "{{ prev_proc|int(0) + cur_val|int(0) }}"
    unit_of_measurement: "rotations/day"
    icon: mdi:calendar-today

  burner_feeder_counter_month:
    friendly_name: "Burner Feeder Counter Month"
    calculation: "{{ states('sensor.burner_feeder_signal')|int(0) }}"
    condition: "{{ (prev_raw|int(0)) == 0 and (cur_raw|int(0)) > 0 }}"
    reset: monthly
    postprocess: "{{ prev_proc|int(0) + cur_val|int(0) }}"
    unit_of_measurement: "rotations/month"
    icon: mdi:calendar-month

  burner_feeder_counter_till_low:
    friendly_name: "Burner Feeder Counter Till Low"
    calculation: "{{ states('sensor.burner_feeder_signal')|int(0) }}"
    condition: "{{ (prev_raw|int(0)) == 0 and (cur_raw|int(0)) > 0 }}"
    # No reset interval defined for this sensor.
    postprocess: "{{ prev_proc|int(0) + cur_val|int(0) }}"
    unit_of_measurement: rotations
    icon: mdi:fuel

Why This Matters

  • Simplicity:
    All processing logic is kept within the sensor configuration, making it easy to adjust and understand.

  • Flexibility:
    Whether you’re reading raw sensor data from a Modbus CSV (using modbus_entity and index) or calculating a value using a template (calculation), you can implement your logic with standard Jinja2 templates.

  • Efficiency:
    Built-in value processing handles the heavy lifting so you can focus on what matters.

I hope this component helps simplify your Modbus sensor setups. I’m eager to hear your thoughts, suggestions, or any issues you might encounter.

Happy automating!
Rostislav

2 Likes