Office Overview

Custom built Raspberry Pi model B used as a room controller and extension of my home assistant installation. Monitoring and controlling devices in the Office utilizing the Room Assistant software.

This device is located in the equipment rack mounted to my office desk. Providing motion sensing and temp readings, not very complex at this point.

Down the road this will interface with LED lighting and any other physical devices that can be automated.

Office Info and Use

The main functions are occupancy and temp sensing. The occupancy sensor is tied to LIFX lights on my desk and a lamp in the room through a home assistant automation to trigger the lights on motion detection.

Hardware

Raspberry pi model 1b is the brain here, providing MQTT communication to the controller and reading sensor inputs via GPIO pins.

  • Motion Sensor (PIR)
  • Temp Sensor (DS18B20)
  • Input Switches (Not Connected)
  • Relay Control (Not Connected)

Network and Power

This lives directly next to network equipment and power on my desk, simple installation.

Controls

Future control of a relay to be added with an LED light strip for accent lighting to the desk.

Temp Sensor

Using a DHT11 sensor and a script to report the temp every min (cron job through room-assistant script.

I’m using the old depreciated Adafruit_Python_DHT library due to issues with the new circuit python version and already having this working.

Room-Assistant config excerpt:

shell:
  sensors:
    # DS18B20 Shelll Sensor
    - name: Office Temperature
      command: 'python3.7 /home/pi/room-assistant/script/temperature_sensor_code.py'
      cron: '* * * * *'
      icon: mdi:temperature-fahrenheit
      unitOfMeasurement: '°F'
      deviceClass: temperature

Mounting

The Raspberry Pi came with a robust aluminum case, which I have modified to mount to a 2 RU blank rack panel, screwed into the 2 post 19” rack rails living on my desk. Simple, industrial and functional.

Software

Everything is controlled and mapped to the home assistant dashboard over MQTT via the room-assistant system.

Room Assistant Config

This config file is the meat and potatoes of the program. Find it in /home/$USER/room-assistant/config/local.yml on the Raspberry Pi.

# ########################
# Raspi Config
#   Office controller - Office Desk
#   hass-raspi2
#   10.10.10.71
# ########################

# ############
# GPIO Pin-Out
# ############
#
# Inputs:
# Pin: 04 Use: ds18b20 temp sensor using the shell functions below
# Pin: 24 Use: Office Light Switch (NC)
# Pin: 25 Use: Office Motion Sensor
# Pin: 35 Use: CPU voltage
#
# Outputs:
# Pin: 17 Use: Office LED (NC) Relay

# #######################
# Global Config settings
# #######################
global:
  instanceName: office
  integrations:
    - homeAssistant
    - gpio
    - shell

# #######################
# Cluster settings
# #######################
# Config options for clustering multiple Room-Assistant
# Give leader more weight
cluster:
  weight: 2
  networkInterface: eth0
  port: 6425
  timeout: 60
  peerAddresses:
    # raspi1 patio
    - 10.10.10.70:6425
    # raspi2 office
#    - 10.10.10.71:6425 <-- this cpu
    # raspi3 sprinkler
    - 10.10.10.72:6425
    #raspi4 kitchen
    - 192.168.1.75:6425
    #raspi5 crawlspace
    - 10.0.0.74:6425
    # raspi6 garage
    - 10.10.10.73:6425

# #######################
# home assistant settings
# #######################
homeAssistant:
#  mqttUrl: mqtt://10.10.10.5:1883
  mqttUrl: mqtt://10.10.10.21:1883
  mqttOptions:
    username: homeassistant
    password: {LONG_RANDOM_STRING}


# #######################
# GPIO settings
# #######################
gpio:
  binarySensors:

    # PIR motion sensor
    - name: Office Motion Sensor
      pin: 25
      deviceClass: motion

    # General Input Switch 
    - name: Office Switch
      pin: 24

# #######################
# Switches settings
# #######################
switches:

    # Output GPIO intended for a relay to switch an LED strip
    - name: Office LED
      pin: 17

# #######################
# Shell settings
# #######################
shell:
  sensors:

     # DS18B20 Shelll Sensor
    - name: Office Temperature
      command: 'python3.7 /home/pi/room-assistant/script/temperature_sensor_code.py'
      cron: '* * * * *'
      icon: mdi:temperature-fahrenheit
      unitOfMeasurement: '°F'
      deviceClass: temperature

    - name: Office CPU Temp
      command: '/home/pi/room-assistant/script/cpuTemp.sh'
      cron: '*/2 * * * *'
      unitOfMeasurement: F
      deviceClass: temperature
    
    # Script to check voltage and return boolean if no errors seen. 
    # See the script for more
    - name: Office CPU Voltage
      command: '/home/pi/room-assistant/script/cpuVolt.sh'
      cron: '1 */1 * * *'
      deviceClass: power

    # Report CPU uptime in sec
    - name: Office CPU Up Time
      command: '/home/pi/room-assistant/script/cpuUp.sh'
      cron: '* * * * *'
      unitOfMeasurement: 's'

    # Free memory `free -h` results
    - name: Office CPU Free Memory
      command: '/home/pi/room-assistant/script/freeMem.sh'
      cron: '*/10 * * * *'
      unitOfMeasurement: 'MB'

#    - name: Office Wifi Strength
#      command: 'iwconfig wlan0 | grep -i quality'
#      regex: 'Signal level=(-?[0-9]+) dBm'
#      cron: '*/30 * * * *'
#      icon: mdi:wifi
#      unitOfMeasurement: dBm
#      deviceClass: signal_strength

#    - name: Office CPU Free Storage
#      command: '/home/pi/room-assistant/script/cpuStorage.sh'
#      cron: '1 * */1 * *'
#      unitOfMeasurement: 'GB'
#      deviceClass: timestamp

# #######################
# Entity settings
# #######################
entities:
  behaviors:
    office_motion_sensor:
      debounce:
        wait: 0.75
        maxWait: 2


Scripts

Some additional helper scripts were also developed to return info on the device for integrations and status’s over in home assistant.

Add these to room assistant using the shell.sensors function like this:

shell:
  sensors:

     # DHT11 Sensor reporting the temp °F result
    - name: Garage Temperature
      command: 'python3.7 /home/pi/room-assistant/script/myDHT.py'
      regex: '(-?[0-9.]+)F'
      cron: '*/2 * * * *'
      icon: mdi:temperature-fahrenheit
      unitOfMeasurement: '°F'
      deviceClass: temperature

cpuUp.sh

return the uptime in seconds formatted as int

#!/bin/bash

echo `cat /proc/uptime |awk '{print $1}' |cut -d '.' -f1`

cpuTemp.sh

return the CPU reported temp

#!/bin/bash

cpuTemp=`vcgencmd measure_temp |cut -d "=" -f2 |cut -d "'" -f1 | awk '{print ($1 *9/5) + 32}'`
echo $cpuTemp


freeMem.sh

returns the remaining RAM on the pi

#!/bin/bash

memfree=`cat /proc/meminfo | grep MemFree | awk '{print $2}'`; 
memtotal=`cat /proc/meminfo | grep MemTotal | awk '{print $2}'`; 


awk '/MemFree/{free=$2} /MemTotal/{total=$2} END{print (free*100)/total}' /proc/meminfo

#echo $(($memfree * 100 / $memtotal))

myDHT.py

adapted DHT11 temp sensor reading temp and humid

import Adafruit_DHT
import time

DHT_SENSOR = Adafruit_DHT.DHT11
DHT_PIN = 27

while True:
    humidity, temperature = Adafruit_DHT.read_retry(DHT_SENSOR, DHT_PIN)
    if humidity is not None and temperature is not None:
        temperature_f = temperature * (9 / 5) + 32
        print("Temp={0:0.1f}F Humidity={1:0.1f}%".format(temperature_f, humidity))
        exit()
    else:
        time.sleep(.05);

temperature_sensor_code.py

read DS18B20 sensor, report value in F


# Temp DS180b20 reading into F result on raspi
#
# https://pimylifeup.com/raspberry-pi-temperature-sensor/
# Modified from
#   - git clone https://github.com/pimylifeup/temperature_sensor.git

import os
import glob
import time

os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')

base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'

def read_temp_raw():
    lines = []
    i = 0
    # try to read the file 20 times, return the result
    while not lines and (i < 19):
        try:
            f = open(device_file, 'r')
            lines = f.readlines()
            i += 1
        except NameError:
            time.sleep(1)
        else:
            if not lines:
                f.close()
            else:
                f.close()
                return lines

def read_temp():
    lines = read_temp_raw()
    if lines[0].strip()[-3:] != 'YES':
        lines = read_temp_raw()
    equals_pos = lines[1].find('t=')
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_c = float(temp_string) / 1000.0
        temp_f = temp_c * 9.0 / 5.0 + 32.0
        return temp_f

# print to reduced decimal place
print('{0:06.3f}'.format(read_temp()))



cpuVolt.sh

return boolean if no issues with voltage (power supply failure)

#!/bin/bash

THROTTLED=`/opt/vc/bin/vcgencmd get_throttled |cut -d "=" -f2`
RESULTS=0

if [[ "$THROTTLED" != *"0x0"*  ]];then
	RESULTS=1
fi

echo $RESULTS