Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set GPIO pin state when initialising #50

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@

mqtt:
host:
port:
user:
password:
host:
port:
user:
password:
# discovery: true #defaults to false, uncomment to enable home-assistant discovery
# discovery_prefix: homeassistant #change to match with setting of home-assistant

doors:
-
id:
# name: #defaults to an unsanitized version of the id paramater
relay:
state:
# state_mode: normally_closed #defaults to normally open, uncomment to switch
# invert_relay: true #defaults to false, uncomment to turn relay pin on by default
state_topic: "home-assistant/cover"
command_topic: "home-assistant/cover/set"
- id:
# name: #defaults to an unsanitized version of the id paramater
relay:
state:
# state_mode: normally_closed #defaults to normally open, uncomment to switch
# invert_relay: true #defaults to false, uncomment to turn relay pin on by default
state_topic: "home-assistant/cover"
command_topic: "home-assistant/cover/set"

2 changes: 1 addition & 1 deletion [email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Type=simple
Restart=always
RestartSec=3
User=%i
ExecStart=/usr/bin/python -u /home/pi/GarageQTPi/main.py
ExecStart=/home/pi/GarageQTPi/venv/bin/python3.9 -u /home/pi/GarageQTPi/main.py

[Install]
WantedBy=multi-user.target
26 changes: 11 additions & 15 deletions lib/garage.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import time
import RPi.GPIO as GPIO
from eventhook import EventHook
from lib.eventhook import EventHook

# S (200ms)
SHORT_WAIT = .2


SHORT_WAIT = .2 #S (200ms)
"""
The purpose of this class is to map the idea of a garage door to the pinouts on
The purpose of this class is to map the idea of a garage door to the pinouts on
the raspberrypi. It provides methods to control the garage door and also provides
and event hook to notify you of the state change. It also doesn't maintain any
state internally but rather relies directly on reading the pin.
"""
class GarageDoor(object):

def __init__(self, config):

# Config
Expand All @@ -28,13 +30,9 @@ def __init__(self, config):
# Set relay pin to output, state pin to input, and add a change listener to the state pin
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(self.relay_pin, GPIO.OUT)
GPIO.setup(self.relay_pin, GPIO.OUT, initial=self.invert_relay)
GPIO.setup(self.state_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(self.state_pin, GPIO.BOTH, callback=self.__stateChanged, bouncetime=300)


# Set default relay state to false (off)
GPIO.output(self.relay_pin, self.invert_relay)
GPIO.add_event_detect(self.state_pin, GPIO.BOTH, callback=self.__state_changed, bouncetime=300)

# Release rpi resources
def __del__(self):
Expand All @@ -58,8 +56,8 @@ def stop(self):
# State is a read only property that actually gets its value from the pin
@property
def state(self):
# Read the mode from the config. Then compare the mode to the current state. IE. If the circuit is normally closed and the state is 1 then the circuit is closed.
# and vice versa for normally open
# Read the mode from the config. Then compare the mode to the current state. IE. If the circuit is normally
# closed and the state is 1 then the circuit is closed and vice versa for normally open
state = GPIO.input(self.state_pin)
if state == self.mode:
return 'closed'
Expand All @@ -72,12 +70,10 @@ def __press(self):
time.sleep(SHORT_WAIT)
GPIO.output(self.relay_pin, self.invert_relay)


# Provide an event for when the state pin changes
def __stateChanged(self, channel):
def __state_changed(self, channel):
if channel == self.state_pin:
# Had some issues getting an accurate value so we are going to wait for a short timeout
# after a statechange and then grab the state
time.sleep(SHORT_WAIT)
self.onStateChange.fire(self.state)

34 changes: 16 additions & 18 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,42 @@

from lib.garage import GarageDoor

print "Welcome to GarageBerryPi!"
print("Welcome to GarageBerryPi!")


# Update the mqtt state topic
def update_state(value, topic):
print "State change triggered: %s -> %s" % (topic, value)

print("State change triggered: %s -> %s" % (topic, value))
client.publish(topic, value, retain=True)


# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, rc):
print "Connected with result code: %s" % mqtt.connack_string(rc)
def on_connect(client, userdata, flags, rc):
print("Connected with result code: %s" % mqtt.connack_string(rc))
for config in CONFIG['doors']:
command_topic = config['command_topic']
print "Listening for commands on %s" % command_topic
print("Listening for commands on %s" % command_topic)
client.subscribe(command_topic)


# Execute the specified command for a door
def execute_command(door, command):
try:
doorName = door.name
except:
doorName = door.id
print "Executing command %s for door %s" % (command, doorName)
print("Executing command %s for door %s" % (command, doorName))
if command == "OPEN" and door.state == 'closed':
door.open()
elif command == "CLOSE" and door.state == 'open':
door.close()
elif command == "STOP":
door.stop()
else:
print "Invalid command: %s" % command
print("Invalid command: %s" % command)

with open(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'config.yaml'), 'r') as ymlfile:
CONFIG = yaml.load(ymlfile)
CONFIG = yaml.safe_load(ymlfile)

### SETUP MQTT ###
user = CONFIG['mqtt']['user']
Expand All @@ -52,7 +54,7 @@ def execute_command(door, command):
else:
discovery_prefix = CONFIG['mqtt']['discovery_prefix']

client = mqtt.Client(client_id="MQTTGarageDoor_" + binascii.b2a_hex(os.urandom(6)), clean_session=True, userdata=None, protocol=4)
client = mqtt.Client(client_id="MQTTGarageDoor_" + (binascii.b2a_hex(os.urandom(6)).decode('utf8')), clean_session=True, userdata=None, protocol=4)

client.on_connect = on_connect

Expand All @@ -72,21 +74,20 @@ def execute_command(door, command):
# Sanitize id value for mqtt
doorCfg['id'] = re.sub('\W+', '', re.sub('\s', ' ', doorCfg['id']))

if discovery is True:
if discovery:
base_topic = discovery_prefix + "/cover/" + doorCfg['id']
config_topic = base_topic + "/config"
doorCfg['command_topic'] = base_topic + "/set"
doorCfg['state_topic'] = base_topic + "/state"

command_topic = doorCfg['command_topic']
state_topic = doorCfg['state_topic']


door = GarageDoor(doorCfg)

# Callback per door that passes a reference to the door
def on_message(client, userdata, msg, door=door):
execute_command(door, str(msg.payload))
execute_command(door, msg.payload.decode('utf-8'))

# Callback per door that passes the doors state topic
def on_state_change(value, topic=state_topic):
Expand All @@ -102,9 +103,6 @@ def on_state_change(value, topic=state_topic):

# If discovery is enabled publish configuration
if discovery is True:
client.publish(config_topic,'{"name": "' + doorCfg['name'] + '", "command_topic": "' + command_topic + '", "state_topic": "' + state_topic + '"}', retain=True)

client.publish(config_topic, '{"name": "' + doorCfg['name'] + '", "command_topic": "' + command_topic + '", "state_topic": "' + state_topic + '"}', retain=True)
# Main loop
client.loop_forever()