Cheap sensors (temperature, motion and light) + MQTT

Updated 08/10/17: python scripts now with username and password for mqtt broker

Here is my attempt to use cheap sensors (like the ones you can get from here: http://camjam.me/?page_id=623 ) with Home Assistant.
I’m using the temperature, motion and light sensors.

I’ve got Home Assistant running on a Pi 3 and a Pi Zero on which I connected the sensors.
The goal is to send the sensor’s data from the pi zero thanks to python scripts to Home assistant through MQTT.

Installation of necessary packages on the Pi Zero (with the sensors):

sudo apt-get install python3 python3-pip
sudo pip3 install paho-mqtt
sudo pip3 install RPi.GPIO

1- Temperature Sensor

On Home Assistant:

Creation of the topic in sensors.yaml:

  - platform: mqtt
    state_topic: "home-assistant/firstfloor/temperature"
    name: First Floor Temperature
    unit_of_measurement: °C

On the Pi Zero:

Creation of the python script:

nano /home/pi/tempmqtt.py

#!/usr/bin/python3
# Import package
import os
import glob
import time
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish

# Def
broker = "192.168.1.29"
state_topic = "home-assistant/firstfloor/temperature"
delay = 30

# Initialize the GPIO Pins
os.system('modprobe w1-gpio') # Turns on the GPIO module
os.system('modprobe w1-therm') # Turns on the Temperature module

# Finds the correct device file that holds the temperature data
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'

# A function that reads the sensors data
def read_temp_raw():
    f = open(device_file, 'r') # Opens the temperature device file
    lines = f.readlines() # Returns the text
    f.close()
    return lines

# Convert the value of the sensor into a temperature
def read_temp():
    lines = read_temp_raw() # Read the temperature 'device file'
    # While the first line does not contain 'YES', wait for 0.2s
    # and then read the device file again.
    while lines[0].strip()[-3:] != 'YES':
        time.sleep(0.2)
        lines = read_temp_raw()

    # Look for the position of the '=' in the second line of the
    # device file.
    equals_pos = lines[1].find('t=')

    # If the '=' is found, convert the rest of the line after the
    # '=' into degrees Celsius
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_c = float(temp_string) / 1000.0
        return temp_c

############### MQTT section ##################

client = mqtt.Client()
client.username_pw_set("username", "password")
client.connect(broker)
client.loop_start()

while True:
    print(read_temp())
    time.sleep(1)
    sensor_data = read_temp()
    client.publish("home-assistant/firstfloor/temperature", str(sensor_data))
    time.sleep(delay)

Give permissions to script:

sudo chmod +x /home/pi/tempmqtt.py

Autorun the python script on boot using systemd:

sudo nano /lib/systemd/system/tempmqtt.service

[Unit]
Description=Temp Mqtt Service
After=multi-user.target

[Service]
Type=idle
ExecStart=/usr/bin/python3 /home/pi/tempmqtt.py

[Install]
WantedBy=multi-user.target

Enable service and reload systemd:

sudo chmod 644 /lib/systemd/system/tempmqtt.service
sudo systemctl daemon-reload
sudo systemctl enable tempmqtt.service

2- Light Sensor

On Home Assistant:

Creation of the topic in sensors.yaml:

sensors.yaml

  - platform: mqtt
    state_topic: "home-assistant/firstfloor/light_intensity"
    name: First Floor Light Intensity

On the Pi Zero:

Creation of the python script:

nano /home/pi/light.py

#!/usr/bin/python3
# Import package
import RPi.GPIO as GPIO
import time
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish

# Def
broker = "192.168.1.29"
state_topic = "home-assistant/firstfloor/light_intensity"
delay = 30

# Import Libraries
import time
import RPi.GPIO as GPIO
# Set the GPIO Mode
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# A variable with the LDR reading pin number
PinLDR = 27

def ReadLDR():
    LDRCount = 0 # Sets the count to 0
    GPIO.setup(PinLDR, GPIO.OUT)
    GPIO.output(PinLDR, GPIO.LOW)
    time.sleep(0.1) # Drains all charge from the capacitor
    GPIO.setup(PinLDR, GPIO.IN) # Sets the pin to be input
    # While the input pin reads ‘off’ or Low, count
    while (GPIO.input(PinLDR) == GPIO.LOW):
        LDRCount += 1 # Add one to the counter
    return LDRCount

############### MQTT section ##################

client = mqtt.Client()
client.username_pw_set("username", "password")
client.connect(broker)
client.loop_start()

while True:
    print(ReadLDR())
    time.sleep(1)
    sensor_data = ReadLDR()
    client.publish("home-assistant/firstfloor/light_intensity", str(sensor_data))
    time.sleep(delay)

Give permissions to script:

sudo chmod +x /home/pi/light.py

Autorun the python script on boot using systemd:

sudo nano /lib/systemd/system/lightmqtt.service

[Unit]
Description=Light Mqtt Service
After=multi-user.target

[Service]
Type=idle
ExecStart=/usr/bin/python3 /home/pi/light.py

[Install]
WantedBy=multi-user.target

Enable service and reload systemd:

sudo chmod 644 /lib/systemd/system/lightmqtt.service
sudo systemctl daemon-reload
sudo systemctl enable lightmqtt.service

3- PIR Sensor

On Home Assistant:

Creation of the topic in sensors.yaml:

sensors.yaml

  - platform: mqtt
    state_topic: "home-assistant/firstfloor/motion"
    name: First Floor Motion Detector

On the Pi Zero:

Creation of the python script:

nano /home/pi/pir.py

#!/usr/bin/python3
# Import required Python libraries
import time
import RPi.GPIO as GPIO
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish

# Def
broker = "192.168.1.29"
state_topic = "home-assistant/firstfloor/motion"
auth = {
  'username':"",
  'password':""
}

# Use BCM GPIO references
# instead of physical pin numbers
GPIO.setmode(GPIO.BCM)

# Define GPIO to use on Pi
GPIO_PIR = 17

print ("PIR Module Holding Time Test (CTRL-C to exit)")

# Set pin as input
GPIO.setup(GPIO_PIR,GPIO.IN)      # Echo

Current_State  = 0
Previous_State = 0

#MQTT
client = mqtt.Client()
client.connect(broker)
client.loop_start()

try:

  print ("Waiting for PIR to settle ...")

  # Loop until PIR output is 0
  while GPIO.input(GPIO_PIR)==1:
    Current_State  = 0

  print ("Ready")
  publish.single('home-assistant/firstfloor/motion', 'no motion', hostname=broker, auth=auth)
  
  # Loop until users quits with CTRL-C
  while True:

    # Read PIR state
    Current_State = GPIO.input(GPIO_PIR)

    if Current_State==1 and Previous_State==0:
      # PIR is triggered
      start_time=time.time()
      print ("Motion detected!")
      publish.single('home-assistant/firstfloor/motion', 'motion detected', hostname=broker, auth=auth)
      # Record previous state
      Previous_State=1
    elif Current_State==0 and Previous_State==1:
      # PIR has returned to ready state
      stop_time=time.time()
      print ("Ready "),
      elapsed_time=int(stop_time-start_time)
      print ("(Elapsed time : " + str(elapsed_time) + " secs)")
      Previous_State=0
      publish.single('home-assistant/firstfloor/motion', 'no motion', hostname=broker, auth=auth)

except KeyboardInterrupt:
  print ("Quit")
  # Reset GPIO settings
  GPIO.cleanup()

Give permissions to script:

sudo chmod +x /home/pi/pir.py

Autorun the python script on boot using systemd:

sudo nano /lib/systemd/system/pirmqtt.service

[Unit]
Description=PIR Mqtt Service
After=multi-user.target

[Service]
Type=idle
ExecStart=/usr/bin/python3 /home/pi/pir.py

[Install]
WantedBy=multi-user.target

Enable service and reload systemd:

sudo chmod 644 /lib/systemd/system/pirmqtt.service
sudo systemctl daemon-reload
sudo systemctl enable pirmqtt.service

Restart Home assistant and reboot the Pi Zero.
Et Voilà!

AUTOMATION EXAMPLES:

These ones are for my entrance hallway which is always a pretty dark room unfortunately:

The light is turned on automatically when motion is detected and the light sensor readings are above 1400 (which is when it is getting too dark for me)

- alias: Turn on hallway light when motion is detected
  initial_state: True
  trigger:
    - platform: state
      entity_id: sensor.hallway_motion_detector
      to: 'motion detected'
  condition:
    condition: numeric_state
    entity_id: sensor.hallway_light_intensity
    above: 1400
  action:
    - service: light.turn_on
      data:
        entity_id: light.hue_white_lamp_1
    - service: light.hue_activate_scene
      data:
        group_name: "Hallway"
        scene_name: "Dimmed"

The light stays on as long as there is motion detected and then turned off after a few seconds.

- alias: Turn off hallway light when no motion is detected
  initial_state: True
  trigger:
    - platform: state
      entity_id: sensor.hallway_motion_detector
      to: 'no motion'
      for:
        seconds: 17
  condition:
    condition: time
    after: '08:00:00'
    before: '20:30:00'
  action:
    service: light.turn_off
    data:
      entity_id: light.hue_white_lamp_1

Night mode:

- alias: Hallway light night mode
  initial_state: True
  trigger:
    - platform: state
      entity_id: sensor.hallway_motion_detector
      to: 'no motion'
      for:
        seconds: 17
  condition:
    condition: time
    after: '20:30:01'
    before: '07:59:59'
  action:
    - service: light.turn_on
      data:
        entity_id: light.hue_white_lamp_1
    - service: light.hue_activate_scene
      data:
        group_name: "Hallway"
        scene_name: "Nightlight"

CONCLUSION:

The sensors are pretty reliable and i’ve been using them for my hallway for a few months now.
The only problem being the motion sensor which is really tricky to calibrate…

4 Likes

Thanks for sharing this.

May I know where to enter MQTT username and password in the script?

Can I use DHT22 sensor and BH1750 on this?

Well I’m no expert on MQTT, but as far as I understand the thing, you don’t need to provide id and password of your MQTT broker in the python scripts to publish a message. At least I didn’t have to… I am using Mosquitto as a broker.
Someone please tell me if I’m talking nonsense…

Edit: Stupid me had " allow_anonymous true " in my mosquitto.conf …

I don’t know the DHT22 and BH1750 sensors. The script for temperature will work only with a DS18B20 Digital temperature sensor ( https://www.adafruit.com/product/381 ) and the one for light with a cheap light dependent resistor.

But if you already have a script that reads data from those sensors, you could just add the MQTT part to the code. That’s what I did basically.

It depends on your broker setting. By default no username and password is set. I changed that to use username and password.

I have updated the python scripts which should now work with username and password.

Awesome Tutorial, @barbarin, but my motion sensor`s status shows as unknown on HA page.
Got it all setup accordingly, but instead of having a separate yaml file for sensors, I just added it to the confi.yaml file. Is this the source of the problem?
I also dont see anything getting published on mosquitto_sub -v -t …

I am using a HC-SR501 motion sensor, which has the same output as the one mentioned above.
Any info will be appreciated.

Cheers,
Antonio Santos

@Antonio_Santos I need to see your code

Hello @barbarin, thanks for the follow-up.

I ended using a python script to read the sensor’s output and publish status to mosquitto. The challenge now has been getting the python script to run as the rpi boots.
The script I used was a combination of the one above and a couple of others and it works fine, but only when run manually.
Already tried playing with pirmqtt.service file for a while, but no success so far.
Any other direction I should take to get it solved?

Thanks a bunch
Cheers,
Antonio

@Antonio_Santos Check the status of your service. What does it say?
Otherwise, you could always try to launch it at boot with your crontab…

Hello @barbarin,

This what shows up when I hit systemcytl:
UNIT LOAD ACTIVE SUB
pirmqtt.service loaded failed failed Pir MQTT SERVICE

All other services start normally, but not mine.

I didnt want to do it contrab, as it’ll one more thing running on it.

Any help is greatly appreciated.

Cheers from BR!

@Antonio_Santos let me see your python script and your service file.

hi!

It’s long, but it’s all here - thank you so much for your time!

#!/usr/bin/python

import time
import RPi.GPIO as GPIO
import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish

Def
broker = “…”
state_topic = “home-assistant/fundos/motion”
auth = {
‘username’:"…",
‘password’:"…"
}

Use BCM GPIO references
instead of physical pin numbers
GPIO.setmode(GPIO.BCM)

Define GPIO to use on Pi
GPIO_PIR = 17

print (“PIR Module Holding Time Test (CTRL-C to exit)”)

Set pin as input
GPIO.setup(GPIO_PIR,GPIO.IN) # Echo

Current_State = 0
Previous_State = 0

#MQTT
client = mqtt.Client()
client.connect(broker)
client.loop_start()

try:

print (“Waiting for PIR to settle …”)

Loop until PIR output is 0
while GPIO.input(GPIO_PIR)==1:
Current_State = 0

print (“Ready”)
publish.single(‘home-assistant/fundos/motion’, ‘no motion’, hostname=broker, auth=auth)

Loop until users quits with CTRL-C
while True:

  • #Read PIR state
    Current_State = GPIO.input(GPIO_PIR)

if Current_State==1 and Previous_State==0:

PIR is triggered

start_time=time.time()
print (“Motion detected!”)
publish.single(‘home-assistant/fundos/motion’, ‘motion detected’, hostname=broker, auth=auth)
-# Record previous state
Previous_State=0
elif Current_State==0 and Previous_State==1:
-# PIR has returned to ready state
stop_time=time.time()
print (“Ready “),
elapsed_time=int(stop_time-start_time)
print (”(Elapsed time : " + str(elapsed_time) + " secs)”)
Previous_State=0
publish.single(‘home-assistant/fundos/motion’, ‘no motion’, hostname=broker, auth=auth)
except KeyboardInterrupt:
print (“Quit”)

Reset GPIO settings
GPIO.cleanup()
This is my .service file config:

[Unit]
Description=PIR Mqtt Service
After=multi-user.target

[Service]
Type=idle
ExecStart=/usr/bin/python /home/pi/pir.py > /home/pi/pir.log 2>&1
Restart=always
StandardOutput=syslog
StandardError=syslog
User=root

[Install]
WantedBy=multi-user.target

I have tried contrab, rc.local, systemd, init.d, etc. All shows the following status:
● pirmqtt.service - PIR Mqtt Service
Loaded: loaded (/lib/systemd/system/pirmqtt.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Tue 2018-01-30 04:36:51 +03; 16min ago
Process: 570 ExecStart=/usr/bin/python /home/pi/pir.py > /home/pi/pir.log 2>&1 (code=exited, status=1/FAILURE)
Main PID: 570 (code=exited, status=1/FAILURE)

THANK YOU FOR ANY #TIME/ATTENTION!

If you are still looking for a script for dht22 that will post the readings to mqtt here is the one I use:

#!/usr/bin/env python
import time
import Adafruit_DHT as dht
import paho.mqtt.client as paho

def read_DHT():
        h,t = dht.read_retry(dht.DHT22, 4)
        print h, t
        t = format(t, '.2f')
        h = format(h, '.2f')
        return(t,h)

if __name__ == '__main__':
#       t,h = read_DHT()
        client = paho.Client()
        client.username_pw_set("your_mqtt_username", "your_mqtt_password")
        client.connect("192.168.0.13", 1883)
        temperature, h  = read_DHT()
        client.publish("room/temperature", str(temperature), qos=1)
        time.sleep(1)
        client.publish("room/humidity", str(h), qos=1)
        client.disconnect()

You need to install Adafruit_DHT module.

@Antonio_Santos what version of python are you using? that might be the problem. Can’t see anything else…
Also why do you launch your service file as root?

I’ll check once I get home, but as far as I undertood, all services started by systemd starts as root already…does it?
On the python version piece, would it be an issue even if it works when run manually? I’ll make sure it’s updated on my raspberry pi anyway.

Thank you for following-up. This seems so simple, but it’s been holding me on everything else, as I dont want to move with unfinished issues.

@Antonio_Santos How do you launch your python script manually? If you type /usr/bin/python /home/pi/pir.py in your terminal, is it working?

Yes, it does, @barbarin!

My pi has python 2.7.13 and python 3.5.3

@Antonio_Santos have you tried removing user=root from your system file? I’m running out of ideas…

Just did! Really dont know whatelse to try!
Thanks a lot anyway!

And if you use python 3 instead of python 2?