Added topic chaning for switch open/close

This commit is contained in:
Ondrej Mikle 2017-10-29 15:39:09 +01:00
parent 388d8a80b0
commit ef1d8b8080
2 changed files with 83 additions and 18 deletions

View file

@ -42,10 +42,13 @@ channels = #test-bjornbot
tls = True tls = True
reconnect_delay = 300 reconnect_delay = 300
[open-switch] [open_switch]
# Controls showing status of "OPEN/CLOSE" switch that is connected to some GPIO pin # Controls showing status of "OPEN/CLOSE" switch that is connected to some GPIO pin
# Changes topic of connected IRC channels if IRC is enabled # Changes topic of connected IRC channels if IRC is enabled
# There is no point in enabling this if you disabled IRC
# enabled - True/False # enabled - True/False
# status_file - file in sysfs that contains 1 or 0 defining the state of button # status_file - file in sysfs that contains 1 or 0 defining the state of button
# open_value - which value in status_file respresents the switch being in "OPEN" position, 1 character
enabled = True enabled = True
status_file = /sys/class/gpio/gpio11/value status_file = /sys/class/gpio/gpio11/value
open_value = 1

View file

@ -8,6 +8,7 @@ import threading
import irc.client import irc.client
import ssl import ssl
import Queue import Queue
import re
from binascii import hexlify from binascii import hexlify
from functools import partial from functools import partial
@ -57,11 +58,15 @@ class BrmdoorConfig(object):
self.ircNick = self.config.get("irc", "nick") self.ircNick = self.config.get("irc", "nick")
self.ircPassword = self.config.get("irc", "password") if self.config.has_option("irc", "password") else None self.ircPassword = self.config.get("irc", "password") if self.config.has_option("irc", "password") else None
self.ircChannels = self.config.get("irc", "channels").split(" ") self.ircChannels = self.config.get("irc", "channels").split(" ")
if len(self.ircChannels) < 1:
print >> sys.stderr, "You must specify at least one channel for IRC when IRC is enabled"
sys.exit(1)
self.ircUseTLS = self.config.getboolean("irc", "tls") self.ircUseTLS = self.config.getboolean("irc", "tls")
self.ircReconnectDelay = self.config.getint("irc", "reconnect_delay") self.ircReconnectDelay = self.config.getint("irc", "reconnect_delay")
self.useOpenSwitch = self.config.getboolean("open-switch", "enabled") self.useOpenSwitch = self.config.getboolean("open_switch", "enabled")
if self.useOpenSwitch: if self.useOpenSwitch:
self.switchStatusFile = self.config.get("open-switch", "status_file") self.switchStatusFile = self.config.get("open_switch", "status_file")
self.switchOpenValue = self.config.get("open_switch", "open_value")
def convertLoglevel(self, levelString): def convertLoglevel(self, levelString):
"""Converts string 'debug', 'info', etc. into corresponding """Converts string 'debug', 'info', etc. into corresponding
@ -197,6 +202,7 @@ class IrcThread(threading.Thread):
self.reactor = None self.reactor = None
self.connected = False self.connected = False
self.threadLock = threading.Lock() self.threadLock = threading.Lock()
self.connection = None
threading.Thread.__init__(self) threading.Thread.__init__(self)
@ -230,6 +236,14 @@ class IrcThread(threading.Thread):
logging.error("Could not connect to IRC server: %s", e) logging.error("Could not connect to IRC server: %s", e)
return False return False
def getTopic(self, channel):
with self.threadLock:
return self.connection.topic(channel)
def setTopic(self, channel, newTopic):
with self.threadLock:
return self.connection.topic(channel, newTopic)
def onConnect(self, connection, event): def onConnect(self, connection, event):
for channel in self.channels: for channel in self.channels:
connection.join(channel) connection.join(channel)
@ -240,24 +254,32 @@ class IrcThread(threading.Thread):
time.sleep(self.reconnectDelay) time.sleep(self.reconnectDelay)
self.setConnected(self.connect()) self.setConnected(self.connect())
def onJoin(self, connection, event):
logging.info("Joined channel, event: %s", event)
connection.privmsg(self.channels[0], "brmbot-libfc starting")
def run(self): def run(self):
logging.debug("Starting IRC thread") logging.debug("Starting IRC thread")
while True: while True:
connected = self.connect() try:
logging.info("IRC connected: %s", connected) connected = self.connect()
self.setConnected(connected) logging.info("IRC connected: %s", connected)
self.connection.add_global_handler("welcome", partial(IrcThread.onConnect, self)) self.setConnected(connected)
self.connection.add_global_handler("disconnect", partial(IrcThread.onDisconnect, self)) self.connection.add_global_handler("welcome", partial(IrcThread.onConnect, self))
self.connection.add_global_handler("disconnect", partial(IrcThread.onDisconnect, self))
self.connection.add_global_handler("join", partial(IrcThread.onJoin, self))
while self.getConnected(): while self.getConnected():
self.reactor.process_once(timeout=5) self.reactor.process_once(timeout=5)
try: try:
msg = self.msgQueue.get_nowait() with self.threadLock:
self.connection.privmsg_many(self.channels, msg) msg = self.msgQueue.get_nowait()
except Queue.Empty: self.connection.privmsg_many(self.channels, msg)
pass except Queue.Empty:
else: pass
time.sleep(self.reconnectDelay) except Exception:
logging.exception("Exception in IRC thread")
time.sleep(self.reconnectDelay)
class OpenSwitchThread(threading.Thread): class OpenSwitchThread(threading.Thread):
""" """
@ -270,12 +292,46 @@ class OpenSwitchThread(threading.Thread):
:param config - BrmdoorConfig object :param config - BrmdoorConfig object
:param ircThread: IrcThread through which we can set and receive current topics :param ircThread: IrcThread through which we can set and receive current topics
""" """
self.statusFile = config.statusFile self.statusFile = config.switchStatusFile
self.openValue = config.switchOpenValue
self.ircThread = ircThread
threading.Thread.__init__(self) threading.Thread.__init__(self)
def run(self): def run(self):
logging.info("Switch thread start")
if self.ircThread is None: #no point in running this thread if we can't report it anywhere
return
lastStatus = None #Some random value so that first time it will be registered as change
while True: while True:
try:
switchFile = open(self.statusFile)
status = switchFile.read(1)
switchFile.close()
if status != lastStatus:
logging.info("Open switch status changed, new status: %s", status)
lastStatus = status
if status == self.openValue:
strStatus = "OPEN |"
else:
strStatus = "CLOSED |"
if self.ircThread.connected:
for channel in self.ircThread.channels:
topic = self.ircThread.getTopic(channel)
if not topic or not re.match(r"^\s*(OPEN|CLOSED) \|", topic):
newTopic = strStatus
else:
newTopic = re.sub(r"^\s*(OPEN|CLOSED) \|", strStatus, topic)
self.ircThread.setTopic(channel, newTopic)
except (IOError, OSError):
logging.exception("Could not read switch status")
pass #silently ignore non-existent file and other errors, otherwise it'd spam log
except Exception:
logging.exception("Exception in open switch thread")
logging.info("Before sleep")
time.sleep(1) time.sleep(1)
logging.info("After sleep")
if __name__ == "__main__": if __name__ == "__main__":
@ -295,10 +351,16 @@ if __name__ == "__main__":
ircMsgQueue = Queue.Queue() ircMsgQueue = Queue.Queue()
ircThread = None ircThread = None
openSwitchThread = None
if config.useIRC: if config.useIRC:
ircThread = IrcThread(config, ircMsgQueue) ircThread = IrcThread(config, ircMsgQueue)
ircThread.setDaemon(True) ircThread.setDaemon(True)
ircThread.start() ircThread.start()
if config.useOpenSwitch:
openSwitchThread = OpenSwitchThread(config, ircThread)
openSwitchThread.setDaemon(True)
openSwitchThread.start()
nfcScanner = NFCScanner(config, ircMsgQueue, ircThread) nfcScanner = NFCScanner(config, ircMsgQueue, ircThread)
nfcScanner.run() nfcScanner.run()