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).
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.
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. 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
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.
- Slave number is the modbus device number. You can chain and conttrol a number of these devices
data_type
ofint16
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
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.
I created a simple lovelace card to provide a status interface. I will likely add a histiry graph of the present value as well.
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 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
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