Skip to content

Instantly share code, notes, and snippets.

@uSlackr
Last active February 3, 2022 16:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uSlackr/7b1d07d42863c75727dc09e8d5d26794 to your computer and use it in GitHub Desktop.
Save uSlackr/7b1d07d42863c75727dc09e8d5d26794 to your computer and use it in GitHub Desktop.
Modbus PID Temp controller with Home Assistant
- id: '164316004444'
alias: Fermenter1 Temp Alarm
description: ''
trigger:
- platform: state
entity_id: binary_sensor.modbus_alm
for:
hours: 0
minutes: 0
# set this the # seconds between sensor updates so we have consitent values in our notification
seconds: 10
to: 'on'
id: Fermenter_1
condition: []
action:
- service: persistent_notification.create
data:
notification_id: temp_high
message: >-
{{ trigger.id }} PV is out of range. Current value is {{
states('sensor.presvalue_4096' ) }}. Set value is: {{
states('sensor.setvalue_4097' ) }}
mode: single
- id: '1643160999999'
alias: Fermenter Temp OK
description: ''
trigger:
- platform: state
entity_id: binary_sensor.modbus_alm
to: 'off'
id: Fermenter_1
condition: []
action:
- service: persistent_notification.dismiss
data:
notification_id: temp_high
- service: notify.persistent_notification
data:
message: >-
{{trigger.id }} Temp alarm cleared. Pres Value is: {{
states('sensor.presvalue_4096' ) }}
mode: single
- id: '4763574657234654'
alias: Fermenter_1 Temp Set
description: ''
trigger:
- platform: state
entity_id: input_boolean.set_ferm_temp
to: 'on'
condition: []
action:
- service: modbus.write_register
data:
address: 4097
unit: 1
value: 224
hub: hub4
mode: single
modbus:
- name: hub4
type: serial
baudrate: 9600
bytesize: 7
method: ascii
parity: E
port: /dev/ttyUSB0
stopbits: 1
sensors:
- name: "PresValue (4096)"
# friendly_name: "Current temp"
# Monitor PV for Display, history & alerts
slave: 1
address: 4096 # 4097 - 1
scan_interval: 10
data_type: int16
scale: 0.1
precision: 1
device_class: temperature
input_type: holding
- name: "SetValue (4097)"
# friendly_name: "Temp setting"
# Monitor SV for display & history
slave: 1
address: 4097 # 4098 - 1
scan_interval: 10
data_type: int16
scale: 0.1
precision: 1
device_class: temperature
input_type: holding
- name: "Alm1_DevHigh (4132)"
# friendly_name: "Alarm1 Deviation high"
# Monitor for display,history
slave: 1
address: 4132
scan_interval: 10
data_type: int16
scale: 0.1
precision: 1
device_class: temperature
input_type: holding
- name: "Alm1_DevLow (4133)"
# friendly_name: "Alarm1 Deviation low"
# Monitor for display, history
slave: 1
address: 4133
scan_interval: 10
data_type: int16
scale: 0.1
precision: 1
device_class: temperature
input_type: holding
binary_sensors:
# Monitor alarm 1 LED status
- name: "modbus_Alm"
slave: 1
scan_interval: 10
address: 2051 # Alarm 1 LED status register is 2052 - subtract 1 for 0-based
device_class: problem
input_type: discrete_input

Background

I was asked by a pro-brewer to help him monitor fermentation temp control. In a pro brewery, fermentation control is the key to good and repeatable outcome (aka "good beer"). He uses Solo 4848 PID controllers from Automation Direct inside the brewey to monitor and control temps. What he asked of me was a way to monitor and control the controller(s).

Getting started

My first goal was to connect it to a PC. I purchased a USB <=> RS485 adapter off Amazon and a RTD temp probe for testing. He provided the Solo 4848. Next I downloaded the Solo Configuration software from AutomationDirect. It's free and helped we understand what what happening in the device.
To control the controller via modbus, you must set the On-line Configuration parameter (Cosh, P3-12) to on. This is done through the faceplate controls.
Once set, I was able to see the device with the Solo software via modbus communications.

Once I had this working, I my next goal was get it into Home Assistant using their modbus integration. I saw HA a solid way to monitor, record and alert.

HA config

When you plug the USB into Home Assistant (I'm using a blue device; a pi would be similar), you need to find the USB port. Go to Add-ons, Backups and Supervisor and choose System. Click the three dots under Host and select Hardware. image Locate the device that is your new UART device. Best way to do this is observe the list first, then plug in your device and review the list again. Having that information led to this basic modbus config which enabled th integration:

modbus:
  - name: hub4
    type: serial
    baudrate: 9600
    bytesize: 7
    method: ascii
    parity: E
    port: /dev/ttyUSB0
    stopbits: 1

Sensors

Next we need sensors to both read data from the device and sense alarm status.
These two sensors read the PV (Present Value) and SV (Set Value)

      - name: "PresValue (4096)"
        # friendly_name: "Current temp"
        # Monitor PV for history & alerts
        # unit_of_measurement: °C (do not use as int16 is not accurate temp in C - use template)
        slave: 1
        address: 4096 # 4097 - 1
        scan_interval: 10
        data_type: int16
        scale: 0.1
        precision: 1
        device_class: temperature
        input_type: holding
      - name: "SetValue (4097)"
        # friendly_name: "Temp setting"
        # Monitor SV for history
        # unit_of_measurement: °C (do not use as int16 is not accurate temp in C - use template)
        slave: 1
        address: 4097 # 4098 - 1
        scan_interval: 10
        data_type: int16
        scale: 0.1
        precision: 1
        device_class: temperature
        input_type: holding

Notes:

  • You can see in the documentation snippet the SV address is 44098. Modbus register addresses are zero based. For the Solo Devices, the registers in the documents had to be reduced by one to get the modbus address. We also have to drop the leading "4" as this actually represents the modbus function. You can see in our config the address we use for SV is 4097. We can use that address to both read and write the setting. image
  • Slave number is the modbus device number. You can chain and conttrol a number of these devices
  • data_type of int16 works for most values. Even though some of the stored value are floats, they are communicated as ints. (I'll confess to not completely understanding this)
  • To that end, setting the scale: 0.1 allowed home assistant to interpret the number correctly (225 => 22.5)
  • My thread in the [HA community forum] (https://community.home-assistant.io/t/modbus-challenge/380682) was very helpful thanks to nikito7. As was the Wikipedia article on modbus

Binary sensors

Alarms in the Solo Device are detected by reading their status from a bit register. These are read as binary sensors of type: discrete_input

    binary_sensors:
    # Monitor alarm 1 LED status
      - name: "modbus_Alm_1"
        slave: 1
        scan_interval: 10
        address: 2051 # Alarm 1 LED status register is 2052 - subtract 1 for 0-based
        device_class: problem
        input_type: discrete_input

Again the address is zero based so I subtracted one from the documented address.

User Interface

I created a simple lovelace card to provide a status interface. I will likely add a histiry graph of the present value as well. image

Automations

The power of Home Assistant in this scenario is its ability to watch the state of the alarm and send alerts if things go south. The first automation detects an alarm conditions and sets a persistent alert

alias: Fermenter1 Temp Alarm
description: ''
trigger:
  - platform: state
    entity_id: binary_sensor.modbus_alm
    for:
      hours: 0
      minutes: 0
      seconds: 0
    to: 'on'
    id: Fermenter_1
condition: []
action:
  - service: persistent_notification.create
    data:
      notification_id: temp_high
      message: >-
        {{ trigger.id }} PV is out of range. Current value is {{
        states('sensor.presvalue_4096' ) }}.  Set value is: {{
        states('sensor.setvalue_4097' ) }}
mode: single

One interesting piece here is using a template in the notification to report the current and set value image The second interesting part is the use of trigger_ids to report which fermenter reported the issue. Also note the 10 second delay before the Notification goes out. With 10 seconds between device reports, we want to make sure all of the registers update before reporting them in the notification

The second automation clears the persistent alert and reports the current temp.

alias: Fermenter Temp OK
description: ''
trigger:
  - platform: state
    entity_id: binary_sensor.modbus_alm
    to: 'off'
    id: Fermenter_1
condition: []
action:
  - service: persistent_notification.dismiss
    data:
      notification_id: temp_high
  - service: notify.persistent_notification
    data:
      message: >-
        {{trigger.id }} Temp alarm cleared. Pres Value is: {{
        states('sensor.presvalue_4096' ) }}
mode: single

Service Calls

While not implemented in config yet, we are able to manipulate the settings of the device using the service call Modbus: Write register Here is a sample automation that would set the temp. The important part is converting the float to an int (by multiplying by 10). 224 was converted by the device to 22.4

alias: Fermenter_1 Temp Set
description: ''
trigger:
  - platform: state
    entity_id: input_boolean.set_ferm_temp
    to: 'on'
condition: []
action:
  - service: modbus.write_register
    data:
      address: 4097
      unit: 1
      value: 224
      hub: hub4
mode: single
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment