193 lines
6.7 KiB
Python
193 lines
6.7 KiB
Python
import RPi.GPIO as GPIO
|
|
import logging
|
|
import logging.handlers as handlers
|
|
import time
|
|
from threading import Thread
|
|
import cherrypy # https://docs.cherrypy.org/en/latest/tutorials.html#tutorial-1-a-basic-web-application
|
|
import requests, json
|
|
import datetime
|
|
|
|
cherrypy.config.update({
|
|
'server.socket_host' : '0.0.0.0',
|
|
'server.socket_port' : 8081,
|
|
'log.screen' : False
|
|
})
|
|
|
|
logger = logging.getLogger('Rotating Log')
|
|
logger.setLevel(logging.INFO)
|
|
logHandler = handlers.RotatingFileHandler('/home/pi/garage.log', maxBytes=1000000, backupCount=2)
|
|
logHandler.setLevel(logging.INFO)
|
|
logHandler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s - %(message)s', '%Y-%m-%d %H:%M:%S'))
|
|
logger.addHandler(logHandler)
|
|
|
|
|
|
PIN_GARAGE_BUTTON = 23
|
|
PIN_GATE_BUTTON = 24
|
|
PIN_GARAGE = 21
|
|
PIN_GATE = 26
|
|
PIN_LED = 11
|
|
PIN_DOOR_OPEN = 6
|
|
PIN_DOOR_CLOSED = 13
|
|
PIN_SENSOR_GATE= 19
|
|
|
|
|
|
GPIO.setmode(GPIO.BCM)
|
|
GPIO.setup(PIN_GARAGE_BUTTON, GPIO.IN, GPIO.PUD_UP)
|
|
GPIO.setup(PIN_GATE_BUTTON, GPIO.IN, GPIO.PUD_UP)
|
|
GPIO.setup(PIN_GARAGE, GPIO.OUT)
|
|
GPIO.setup(PIN_GATE, GPIO.OUT)
|
|
GPIO.setup(PIN_LED, GPIO.OUT)
|
|
GPIO.setup(PIN_DOOR_OPEN, GPIO.IN, GPIO.PUD_UP)
|
|
GPIO.setup(PIN_DOOR_CLOSED, GPIO.IN, GPIO.PUD_UP)
|
|
GPIO.setup(PIN_SENSOR_GATE, GPIO.IN, GPIO.PUD_UP)
|
|
|
|
def pushover(message):
|
|
response = requests.post("https://api.pushover.net/1/messages.json", data = {
|
|
"token": "a9k1uyzypuaz1yszqqdzmp17s6r5q2",
|
|
"user": "ukja84pd2n2cmxvdrnfwdrf8eo1wc5",
|
|
"message": message
|
|
})
|
|
logger.info(response)
|
|
|
|
def logpush(message):
|
|
logger.info(message)
|
|
Thread(target=pushover,args=[message]).start()
|
|
|
|
# move robomower into safe zone
|
|
def mower_safety():
|
|
try:
|
|
response = requests.get("http://192.168.178.54/json?cmd=status&user=lewe&pass=nFdcX3sMD115WAap")
|
|
except requests.exceptions.RequestException as e:
|
|
logpush("couldn't reach mower (retrieving status)")
|
|
return None
|
|
status = json.loads(response.text)
|
|
if (status["status"]["status"] in [2, 3, 5]):
|
|
logger.info("mower, freeze")
|
|
try:
|
|
#response = requests.get("http://192.168.178.54/json?cmd=mode&mode=job&remotestart=2&user=lewe&pass=nFdcX3sMD115WAap")
|
|
response = requests.get("http://192.168.178.54/json?cmd=stop&user=lewe&pass=nFdcX3sMD115WAap")
|
|
except requests.exceptions.RequestException as e:
|
|
logpush("couldn't reach mower (freeze)")
|
|
else:
|
|
if (status["status"]["status"] == 17 and (datetime.datetime.now().hour < 6 or datetime.datetime.now().hour > 13)):
|
|
logger.info("mower's asleep, leave it alone")
|
|
else:
|
|
logger.info("lock mower in garage")
|
|
try:
|
|
response = requests.get("http://192.168.178.54/json?cmd=mode&mode=home&user=lewe&pass=nFdcX3sMD115WAap")
|
|
except requests.exceptions.RequestException as e:
|
|
logpush("couldn't reach mower (lock)")
|
|
|
|
|
|
# robomower back to auto mode after gate has been closed
|
|
def mower_auto():
|
|
logger.info("set mower back to auto mode")
|
|
try:
|
|
response = requests.get("http://192.168.178.54/json?cmd=mode&mode=auto&user=lewe&pass=nFdcX3sMD115WAap")
|
|
except requests.exceptions.RequestException as e:
|
|
logpush("couldn't reach mower (auto mode)")
|
|
return None
|
|
|
|
def garage_button(channel):
|
|
time.sleep(0.01) # el cheapo relay module creates lots of interference, so we check again after a waiting period (see https://electronics.stackexchange.com/a/361793/253533)
|
|
if channel == 0 or GPIO.input(PIN_GARAGE_BUTTON) == GPIO.LOW:
|
|
logger.info("trigger motor")
|
|
GPIO.output(PIN_GARAGE, GPIO.LOW)
|
|
GPIO.output(PIN_LED, GPIO.HIGH)
|
|
time.sleep(0.4)
|
|
GPIO.output(PIN_GARAGE, GPIO.HIGH)
|
|
GPIO.output(PIN_LED, GPIO.LOW)
|
|
else:
|
|
logger.info("flare (motor button)")
|
|
|
|
def gate_button(channel):
|
|
time.sleep(0.01)
|
|
if channel == 0 or GPIO.input(PIN_GATE_BUTTON) == GPIO.LOW:
|
|
toSafety = False
|
|
if GPIO.input(PIN_SENSOR_GATE) == 0:
|
|
toSafety = True
|
|
|
|
logger.info("trigger gate")
|
|
GPIO.output(PIN_GATE, GPIO.HIGH)
|
|
GPIO.output(PIN_LED, GPIO.HIGH)
|
|
time.sleep(0.4)
|
|
GPIO.output(PIN_GATE, GPIO.LOW)
|
|
GPIO.output(PIN_LED, GPIO.LOW)
|
|
|
|
if toSafety == True:
|
|
mower_safety()
|
|
else:
|
|
mower_auto()
|
|
else:
|
|
logger.info("flare (gate button)")
|
|
|
|
GPIO.add_event_detect(PIN_GARAGE_BUTTON, GPIO.FALLING, callback=garage_button, bouncetime=250)
|
|
GPIO.add_event_detect(PIN_GATE_BUTTON, GPIO.FALLING, callback=gate_button, bouncetime=250)
|
|
|
|
GPIO.output(PIN_GARAGE, GPIO.HIGH)
|
|
GPIO.output(PIN_GATE, GPIO.LOW)
|
|
GPIO.output(PIN_LED, GPIO.LOW)
|
|
|
|
|
|
class GarageService(object):
|
|
@cherrypy.expose
|
|
def index(self):
|
|
return "Hello World!"
|
|
|
|
# deprecated
|
|
# @cherrypy.expose
|
|
# def motor(self):
|
|
# Thread(target=garage_button,args=[0]).start()
|
|
# return "trigger garage door"
|
|
|
|
# deprecated
|
|
# @cherrypy.expose
|
|
# def remote(self):
|
|
# Thread(target=gate_button,args=[0]).start()
|
|
# return "trigger gate"
|
|
|
|
@cherrypy.expose
|
|
def garage(self, action=None):
|
|
if (action == "open" and GPIO.input(PIN_DOOR_CLOSED) and not GPIO.input(PIN_DOOR_OPEN)):
|
|
Thread(target=garage_button,args=[0]).start()
|
|
return '{ "action": "open" }'
|
|
elif (action == "close" and GPIO.input(PIN_DOOR_OPEN) and not GPIO.input(PIN_DOOR_CLOSED)):
|
|
Thread(target=garage_button,args=[0]).start()
|
|
return '{ "action": "close" }'
|
|
if (GPIO.input(PIN_DOOR_OPEN) and not GPIO.input(PIN_DOOR_CLOSED)):
|
|
status = "true"
|
|
else:
|
|
status = "false"
|
|
return '{ "status": ' + status + ' }'
|
|
|
|
@cherrypy.expose
|
|
def gate(self, action=None):
|
|
if (action == "open" and not GPIO.input(PIN_SENSOR_GATE)):
|
|
Thread(target=gate_button,args=[0]).start()
|
|
return '{ "action": "open" }'
|
|
elif (action == "close" and GPIO.input(PIN_SENSOR_GATE)):
|
|
Thread(target=gate_button,args=[0]).start()
|
|
return '{ "action": "close" }'
|
|
if GPIO.input(PIN_SENSOR_GATE) == 0:
|
|
status = "false"
|
|
else:
|
|
status = "true"
|
|
return '{ "status": ' + status + ' }'
|
|
|
|
@cherrypy.expose
|
|
def all(self):
|
|
Thread(target=garage_button,args=[0]).start()
|
|
Thread(target=gate_button,args=[0]).start()
|
|
return "trigger all"
|
|
|
|
@cherrypy.expose
|
|
def status(self):
|
|
return '{ "open": ' + str(GPIO.input(PIN_DOOR_OPEN)) + ', "closed": ' + str(GPIO.input(PIN_DOOR_CLOSED)) + ', "gate": ' + str(GPIO.input(PIN_SENSOR_GATE)) + ' }'
|
|
|
|
|
|
|
|
|
|
cherrypy.quickstart(GarageService())
|
|
logger.info('Shutdown')
|
|
logger.info('Reset GPIO configuration and close')
|
|
GPIO.cleanup() |