Howto: Control your Rinnai Hot Water on Demand Heater with Control-R Module

This might be helpful for anyone looking to automate their Rinnai Hot Water on demand heater that has the Control-R WiFi module installed. Rinnai’s wifi integration has been a complete hack from the company for over a year and im happy to finally have some form of a solution to turn recirculation on though OpenHAB.

I do not take credit for this, as i came across some code that gains access to their portal for the necessary commands:

Step 1: Install this on your OH Server: GitHub - explosivo22/rinnaicontrolr: Python interface for the Rinnai Control-R API

Step 2: Edit the following script: /usr/local/lib/python3.6/dist-packages/rinnaicontrolr/base.py

Under the following Line (Line:130):

    def is_heating(self, dev):
        return dev['info']['domestic_combustion'] == 'true'

Add:

    def get_inlet_temperature(self, dev):
        return dev['info']['m08_inlet_temperature']

    def get_outlet_temperature(self, dev):
        return dev['info']['m02_outlet_temperature']

    def start_maintenance_retrieval(self, dev):
        self._set_shadow(dev, 'do_maintenance_retrieval', 'true')

This will allow you to get some statistics from your unit if you wish, Inlet water temperature, Outlet water temperature, and query ‘maintenance’ which is required to refresh/pull these values listed.

Once that is done, create the following script in your Openhab/scripts directory:

rinnai.py

import sys
from rinnaicontrolr import  RinnaiWaterHeater

rinnai = RinnaiWaterHeater('XXemail@email.comXX', 'XXpasswordXX')

for device in rinnai.get_devices():
    if str(sys.argv[1]) == "settemp": #Set the temperature of hot water heater
         rinnai.set_temperature_setpoint(device, sys.argv[2]) # set the temp for the second arguement value

    if str(sys.argv[1]) == "maint": #Start Maintenance retrieval
         rinnai.start_maintenance_retrieval(device)

    if str(sys.argv[1]) == "recirc": #Enable Recirc followed by duration
         rinnai.start_recirculation(device, sys.argv[2]) # Start Recirc with duration variable in minutes

    if str(sys.argv[1]) == "status": #JSON output of status query
          s = ""
          s = s + "{\n"
          s = s + '"TEMP": "%s",\n' % \
          rinnai.get_temperature_setpoint(device)
          s = s + '"isHeating": "%s",\n' % \
          rinnai.is_heating(device)
          s = s + '"isRecirculating": "%s",\n' % \
          rinnai.is_recirculating(device)
          s = s + '"inletTemp": "%s",\n' % \
          rinnai.get_inlet_temperature(device)
          s = s + '"outletTemp": "%s",\n' % \
          rinnai.get_outlet_temperature(device)
          s = s + "}\n"
          print(s)

Create the following files in openhab:

.things

Thing exec:command:rinnai [command="/usr/bin/python3 /etc/openhab/scripts/rinnai.py status", interval=10, timeout=10]

.items

Group Rinnai

Group gRinnai_Parse_json (Rinnai)

String                H_BM_LDRY_Rinnai_JSON                            "Rinnai JSON: [%s]"  {channel="exec:command:rinnai:output"}

Number                H_BM_LDRY_Rinnai_TEMP                       "Current Temperature   [%s °F]"                             (Rinnai,gRinnai_Parse_json)

Number                H_BM_LDRY_Rinnai_SETTEMP                   "Target Temperature   [%s °F]"                              (Rinnai)

Number                H_BM_LDRY_Rinnai_inletTemp "Rinnai Inlet Temperature [%s °F]]" (Rinnai,gRinnai_Parse_json)

Number                H_BM_LDRY_Rinnai_outletTemp "Rinnai Outet Temperature [%s °F]]" (Rinnai,gRinnai_Parse_json)

String                H_BM_LDRY_Rinnai_isHeating "Rinnai Is Heating [%s]" (Rinnai,gRinnai_Parse_json)

String                H_BM_LDRY_Rinnai_isRecirculating "Rinnai is Recirculating [%s]" (Rinnai,gRinnai_Parse_json)

Switch                H_BM_LDRY_Rinnai_RECIRCULATION "Recirculation" (Rinnai) {ga="WaterHeater",expire="1m, command=OFF"}

Number                H_BM_LDRY_Rinnai_RECIRC_DURATION "How long to run Recirc for [%s min]" (Rinnai,gRinnai_Parse_json)

.Rules

var Timer tRinnai_Reschedule_Maint = null  

rule "Rinnai: Parse JSON output to individual Items"
when
   Item H_BM_LDRY_Rinnai_JSON changed
then
logInfo(filename+".R1", "### Rinnai: Parse JSON output to individual Items ###")
{
   val String json = (H_BM_LDRY_Rinnai_JSON.state as StringType).toString
   gRinnai_Parse_json.members.forEach [ value |
      var String name = value.name.replace('H_BM_LDRY_Rinnai_','$.')
      value.postUpdate(transform("JSONPATH", name, json).replaceAll('"',''))
   ]
}
end

rule "Rinnai: Turn Recirculation ON"
when
   Item H_BM_LDRY_Rinnai_RECIRCULATION changed from OFF to ON
then
logInfo(filename+".R2", "### Rinnai: Turn Recirculation ON ###")
{
    executeCommandLine("/usr/bin/python3.6", "/etc/openhab/scripts/rinnai.py", "recirc", H_BM_LDRY_Rinnai_RECIRC_DURATION.state.toString())
}
end



rule "Rinnai: When Heater is Running, Gather Maintenance Stats (Inlet/Outlet Temps)"
when
   Item H_BM_LDRY_Rinnai_isHeating changed from False to True
then
logInfo(filename+".R3", "### Rinnai: When Heater is Running, Gather Maintenance Stats (Inlet/Outlet Temps) ###")
{
   if(tRinnai_Reschedule_Maint === null) {
         tRinnai_Reschedule_Maint = createTimer(now.plusSeconds(30), [ |
         if(H_BM_LDRY_Rinnai_isHeating.state == "True") {
            executeCommandLine("/usr/bin/python3.6", "/etc/openhab/scripts/rinnai.py", "maint")
            logInfo(filename+".R", "--> Gathering Maintenace Information and Rescheduling retrieval")
            tRinnai_Reschedule_Maint.reschedule(now.plusSeconds(30))
         } else {
            logInfo(filename+".R", "<--Canceling Maintenace Retrieval Timer")
            tRinnai_Reschedule_Maint.cancel()
            tRinnai_Reschedule_Maint = null
         } 
         ])
   }
}
end

Hope this helps someone that is looking to acheive the same, If you have any questions just ask!