Help Creating a PID Controller/Thermostat using DHT11 Sensor

  • Platform information:
    • Hardware: Raspberry Pi Zero
    • OS: Raspbian Stretch
    • Java Runtime Environment: 8
    • openHAB version: openHAB 2.5.0.M1 Milestone Build
  • Issue of the topic:
    I’d like to create a PID controller that uses a web GUI to show the temp and allow for adjustments to a given setpoint. I have a few extra DHT11 sensors laying around and would like to use one of those to read both temperature and humidity. Currently I"m using a relay that is controlled by the GPIO pin of the RPi.

I can currently read the temp from the DHT11 using a python script I found on this forum. It reads that out just fine. But when I try and use the exec binding it gives me an error code.

I used the following tutorial to create what I have so far. I will post the items, sitemap and rules files below.

Also any help with creating the buttons to adjust the setpoint would be very helpful. I’d like it to look something like this. In the example provided, the center number (68) is the current temp and he Heat To is the setpoint. When you click on the up and down arrows, it adjusts the setpoint. I"m looking to do something similar to this.

  • Please post configurations (if applicable):

    • PID.Items file –
//-----Proxy items used for logic
Switch Heat "Heat"

//-----Number used for home.sitemap Setpoint
Number:Temperature Setpoint_Temp "PID Setpoint [%.1f °F]" <temperature>

//-----PID_Temp and PID_Hum numbers converted from the strings below (Note: See ../things/PID.things)
Number                 PID_Hum_Numb  "Humidity [%.1f %%]" <humidity>
Number:Temperature     PID_Temp_Numb "Temperature [%.1f °F]" <temperature>

//-----Strings read from DHT11 temp/humidity sensor
String PID_Hum {channel="exec:command:hum:output"}
String PID_Temp {channel="exec:command:temp:output"}

//-----Relay Items used to turn on/off Heat
Switch  Heat_Relay "Heat Relay" {gpio="pin:18 activelow:yes initialValue:high"}
  • pid.sitemap – Sitemap configuration related to the issue
sitemap home label="Gill's Guide Control Center"
{
        Frame label="PID UI"
        {
                Text item=Setpoint_Temp
                Text item=PID_Hum_Numb
                Text item=PID_Temp_Numb
                Switch item=Heat_Relay
        }
}
  • Rules code related to the issue
//-----Used to turn off Heat if Setpoint changed but temp hasn't changed-----//
rule "Update PID Temp Number every minute"
  when
        Time cron "0 0/1 * 1/1 * ? *"
  then
        sendCommand(PID_Temp_Numb.name,PID_Temp_Numb.state.toString)
end

//-----Rule to turn off/on Heat (Auto)-----//
rule "Turn Heat on if Heat switch is ON and PID Temp is greater than Setpoint"
  when
        Item PID_Temp_Numb received command or
        Item PID_Temp_Numb changed
  then
        if (Heat.state==ON && PID_Temp_Numb.state > Setpoint_Temp.state)
    {
        Heat_Relay.sendCommand(ON)
//-----Used to turn off Heat if Setpoint changed but temp hasn't changed-----//
rule "Update PID Temp Number every minute"
  when
        Time cron "0 0/1 * 1/1 * ? *"
  then
        sendCommand(PID_Temp_Numb.name,PID_Temp_Numb.state.toString)
end

//-----Rule to turn off/on Heat (Auto)-----//
rule "Turn Heat on if Heat switch is ON and PID Temp is greater than Setpoint"
  when
        Item PID_Temp_Numb received command or
        Item PID_Temp_Numb changed
  then
        if (Heat.state==ON && PID_Temp_Numb.state > Setpoint_Temp.state)
    {
        Heat_Relay.sendCommand(ON)
        Thread::sleep(5000)
    }
        else
    {
        Heat_Relay.sendCommand(OFF)
        Thread::sleep(5000)
    }

  end

rule "Turn Heat off if Heat switch changes from ON to OFF"
  when
        Item Heat changed from ON to OFF
  then
        Thread::sleep(2000)
        Heat_Relay.sendCommand(OFF)
        Thread::sleep(5000)
  end
  • Scripts related to the issue
    hum.py
#!/usr/bin/env python2.7
import sys

import Adafruit_DHT

sensor = Adafruit_DHT.DHT11

pin = 4

humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)

if humidity is not None and temperature is not None:

     print('{0:0.2f}'.format(humidity))

else:

     print('Failed to get reading. Try again!')

sys.exit(1)

temp.py

#!/usr/bin/env python2.7

import sys

import Adafruit_DHT

sensor = Adafruit_DHT.DHT11

pin = 4

humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)

temperature = temperature * 9/5.0 + 32

if humidity is not None and temperature is not None:

    print('{0:0.2f}'.format(temperature))

else:

    print('Failed to get reading. Try again!')

sys.exit(1)

  • If logs where generated please post these here using code fences:
pi@spid-control:/var/log/openhab2 $ tail -10 events.log
Traceback (most recent call last):
  File "/etc/openhab2/scripts/hum.py", line 10, in <module>
    humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
  File "/usr/local/lib/python2.7/dist-packages/Adafruit_DHT/common.py", line 94, in read_retry
    humidity, temperature = read(sensor, pin, platform)
  File "/usr/local/lib/python2.7/dist-packages/Adafruit_DHT/common.py", line 81, in read
    return platform.read(sensor, pin)
  File "/usr/local/lib/python2.7/dist-packages/Adafruit_DHT/Raspberry_Pi_2.py", line 34, in read
    raise RuntimeError('Error accessing GPIO.')
RuntimeError: Error accessing GPIO.

I forgot to post my things file

PID.Things

Thing exec:command:temp [command="python /etc/openhab2/scripts/temp.py", interval=30, autorun=true]
Thing exec:command:hum [command="python /etc/openhab2/scripts/hum.py", interval=300, autorun=true]


Error accessing GPIO.

Maybe insufficient permission, or another program is blocking access for GPIO.
As the script is almost the same for both values, maybe it would be better get both values in one channel and split them with a rule:

humTemp.py

#!/usr/bin/env python2.7
import sys

import Adafruit_DHT

sensor = Adafruit_DHT.DHT11

pin = 4

humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)

if humidity is not None and temperature is not None:

     print('{0:0.2f}'.format(humidity))
     print('_')
     print('{0:0.2f}'.format(temperature))

else:

     print('Failed to get reading. Try again!')

sys.exit(1)

pid.things

Thing exec:command:humTemp [ command="python /etc/openhab2/scripts/humTemp.py", interval=30 ]

items:

String PID_Output { channel="exec:command:humTemp:output" }
Number PID_Hum "Humidity [%.1f %%]"
Number PID_Temp "Temperature [%.1f °F]"

rule:

rule "read humidity and temperature"
when
    Item PID_Output changed
then
    if(PID_Output.state.toString.contains("_")) {
        PID_Hum.postUpdate(Float::parseFloat(PID_Output.state.toString.split("_").get(0)))
        PID_Temp.postUpdate(Float::parseFloat(PID_Output.state.toString.split("_").get(1)))
    } else 
        logWarn("pid_humTemp","Something went wrong! Message: {}", PID_Output.state)
end

Hey Joseph…

Let me get back to you tomorrow evening, please.

Regards,

Bobby

After looking at the log… seems like the openhab user doesn’t have permission to access gpio.

See this… towards the bottom.

https://docs.openhab.org/installation/linux.html#recommended-additional-setup-steps

Run the command… groups openhab.

If tty and dialout are not in the list, add them with…
sudo adduser openhab dialout
sudo adduser openhab tty

I’ll email you tomorrow regarding the sitemap setpoint.

Hope’s this helps.

Hi Bobby,

Thanks for getting back to me on this. I ended up installing Openhabian and starting over. I had an issue with my sitemaps file when I was troubleshooting things. I ended up going back to my posting here and going through things again. Your help got me a bit further along! Thank you! I finally got the temp and humidity to post correctly.

Now I’m looking for help getting this rules file figured out. I need it to turn the heat on when the heat is lower than the setpoint and off when the setpoint is lower than the current temp reading.

I’ll post updates with what I used for my sitemap here tomorrow.

Thanks again for the help!

Cheers!

Joe

Easy:

rule "switch heat on and off"
when
    Item PID_Temp_Numb changed or
    Item Setpoint_Temp changed
then
    if(!(PID_Temp_Numb.state instanceof Number)) return;
    if(!(Setpoint_Temp.state instanceof Number)) return;
    logInfo("switch_heat","PID_Temp {} Setpoint_Temp {}",(PID_Temp_Numb.state as Number).floatValue,(Setpoint_Temp.state as Number).floatValue)
    if((PID_Temp_Numb.state as Number).floatValue < (Setpoint_Temp.state as Number).floatValue)
        Heat_Relay.sendCommand(ON)
    else
        Heat_Relay.sendCommand(OFF)
end

Please take a look at openhab.log, every time the rule gets triggered, the rule prints a log line with the measurement. Please ensure the values are reasonable (UoM may do funny things…)

Thanks for the help with the rule! That worked perfectly. The sensor values look correct also. I tested the temperature with another known good probe and it matches up.

Here is what I ended up using for my sitemap. This produces exactly what I’m after for usage. Now to work on adding additional relays to control different environmental variables. :slight_smile:

I hope this helps someone else out down the road!

Thanks for all the help!

Thsi is my sitemap file for the PID controller.

sitemap pid label="Gill's Guide Control Center"
{
        Frame label="PID UI"
        {
                Setpoint item=Setpoint_Temp label="Temperature Set Point [%.1f °F]" minValue=32 maxValue=200 step=1
                Switch item=Heat_Relay
                Text item=PID_Temp_Numb
                Text item=PID_Hum_Numb
        }
}