aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilien Cuony <maximilien@theglu.org>2016-09-12 19:20:35 +0200
committerMaximilien Cuony <maximilien@theglu.org>2016-09-12 19:20:35 +0200
commit18fb541004d3666cf722e3eeae8ed9aeab9503d2 (patch)
tree5802e1c9c488b2df4d11bae892fc7164cb9a68de
parent2e679e549baca6d3573dacaa925672189b5e034a (diff)
downloadglutte-serial-web-18fb541004d3666cf722e3eeae8ed9aeab9503d2.tar.gz
glutte-serial-web-18fb541004d3666cf722e3eeae8ed9aeab9503d2.tar.bz2
glutte-serial-web-18fb541004d3666cf722e3eeae8ed9aeab9503d2.zip
Add twitter bot
-rw-r--r--adsl.py206
-rw-r--r--config.py.dist4
-rwxr-xr-xglutte_serial_web.py3
-rwxr-xr-xreboot.sh3
-rw-r--r--requirements.txt1
5 files changed, 217 insertions, 0 deletions
diff --git a/adsl.py b/adsl.py
new file mode 100644
index 0000000..119ad35
--- /dev/null
+++ b/adsl.py
@@ -0,0 +1,206 @@
+#!/usr/bin/env python
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2016 Matthias P. Braendli, Maximilien Cuony
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+from twx.botapi import TelegramBot
+import threading
+import time
+import os
+import datetime
+
+
+import config
+
+
+class Monitor(threading.Thread):
+
+ def __init__(self, ser):
+ threading.Thread.__init__(self)
+
+ self.ser = ser
+ self.reset_states()
+
+ def reset_states(self):
+
+ self.current_state = None
+ self.status_starttime = {}
+ self.status_duration = {}
+ self.last_gps_balise = None
+ self.last_message = None
+ self.last_balise = None
+ self.reseted = False
+
+ def run(self):
+
+ queue = self.ser.register_client()
+
+ while True:
+
+ try:
+ line = queue.popleft()
+ except IndexError:
+ time.sleep(1)
+ line = None
+
+ if line:
+ line = line.strip()
+
+ self.last_message = datetime.datetime.now()
+
+ if line.endswith("common init"):
+ self.reset_states()
+ self.reseted = True
+
+ if "T_GPS" in line:
+ self.last_gps_balise = datetime.datetime.now()
+
+ if "FSM: FSM_" in line:
+ new_state = line.split(' ')[-1]
+
+ if self.current_state:
+ self.status_duration[self.current_state] = datetime.datetime.now() - self.status_starttime[self.current_state]
+
+ self.status_starttime[new_state] = datetime.datetime.now()
+ self.current_state = new_state
+
+ if "FSM: FSM_BALISE_LONGUE" in line or "FSM: FSM_BALISE_SPECIALE" in line:
+ self.last_balise = datetime.datetime.now()
+
+ def alarms(self):
+
+ MAXIMUM_STATES = {
+ 'FSM_OISIF': (10800, '3 hours'),
+ 'FSM_OPEN1': (120, '2 minutes'),
+ 'FSM_OPEN2': (120, '2 minutes'),
+ 'FSM_LETTRE': (120, '2 minutes'),
+ 'FSM_ECOUTE': (120, '2 minutes'),
+ 'FSM_ATTENTE': (120, '2 minutes'),
+ 'FSM_QSO': (1800, '30 minutes'),
+ 'FSM_ANTI_BAVARD': (120, '2 minutes'),
+ 'FSM_BLOQUE': (120, '2 minutes'),
+ 'FSM_TEXTE_73': (120, '2 minutes'),
+ 'FSM_TEXTE_HB9G': (120, '2 minutes'),
+ 'FSM_TEXTE_LONG': (120, '2 minutes'),
+ 'FSM_BALISE_LONGUE': (120, '2 minutes'),
+ 'FSM_BALISE_SPECIALE': (120, '2 minutes'),
+ 'FSM_BALISE_COURTE': (120, '2 minutes'),
+ 'FSM_BALISE_COURTE_OPEN': (120, '2 minutes'),
+ }
+
+ result = []
+
+ if self.reseted:
+ result.append("A reset occured !")
+ self.reseted = False
+
+ if self.last_message and (datetime.datetime.now() - self.last_message).total_seconds() > 300:
+ result.append("No message on UART for more than 5 minutes !")
+
+ if self.last_gps_balise and (datetime.datetime.now() - self.last_gps_balise).total_seconds() > 300:
+ result.append("No GPS for more than 5 minutes !")
+
+ if self.last_balise and (datetime.datetime.now() - self.last_balise).total_seconds() > 10800:
+ result.append("No FSM_BALISE_LONGUE nor FSM_BALISE_SPECIALE for more than 3 hours !")
+
+ if self.current_state and self.current_state in MAXIMUM_STATES and (datetime.datetime.now() - self.status_starttime[self.current_state]).total_seconds() > MAXIMUM_STATES[self.current_state][0] / 10:
+ result.append("The FSM has been in the state {} for more than {} !".format(self.current_state, MAXIMUM_STATES[self.current_state][1]))
+
+ return result
+
+
+class ADSL(threading.Thread):
+
+ def __init__(self, ser):
+ threading.Thread.__init__(self)
+ self.monitor = Monitor(ser)
+
+ def run(self):
+
+ self.monitor.start()
+
+ alarms = []
+
+ if not config.TELEGRAM_API_TOKEN or not config.TELEGRAM_GROUP:
+ print("Telegram not configured, ADSL not running.")
+ return
+
+ bot = TelegramBot(config.TELEGRAM_API_TOKEN)
+ bot.update_bot_info().wait()
+ print("Telegram bot {} ready".format(bot.username))
+
+ offset = None
+
+ bot.send_message(config.TELEGRAM_GROUP, '\xe2\x84\xb9 Hello ! I have been started, so everything has been reset on my side.').wait()
+
+ while True:
+
+ updates = bot.get_updates(offset=offset, limit=1, timeout=15).wait()
+ if updates:
+ offset = updates[0].update_id + 1
+
+ try:
+ if int(updates[0].message.chat.id) == int(config.TELEGRAM_GROUP):
+
+ if updates[0].message.text.startswith('/status'):
+ response = "Here is the current status:\n\n"
+
+ response += "Current state: {}\n".format(self.monitor.current_state)
+ if self.monitor.last_message:
+ response += "Last message: {} ({} seconds ago)\n".format(self.monitor.last_message.strftime("%H:%M:%S %d/%m/%Y"), int((datetime.datetime.now() - self.monitor.last_message).total_seconds()))
+ if self.monitor.last_gps_balise:
+ response += "Last GPS: {} ({} seconds ago)\n".format(self.monitor.last_gps_balise.strftime("%H:%M:%S %d/%m/%Y"), int((datetime.datetime.now() - self.monitor.last_gps_balise).total_seconds()))
+ if self.monitor.last_balise:
+ response += "Last Balise: {} ({} seconds ago)\n".format(self.monitor.last_balise.strftime("%H:%M:%S %d/%m/%Y"), int((datetime.datetime.now() - self.monitor.last_balise).total_seconds()))
+
+ response += "\n"
+
+ for state, starttime in self.monitor.status_starttime.items():
+ response += "{}: Started on {} ({} seconds ago)".format(state, starttime.strftime("%H:%M:%S %d/%m/%Y"), int((datetime.datetime.now() - starttime).total_seconds()))
+
+ if state == self.monitor.current_state:
+ response += ", in progress\n"
+ else:
+ response += ", duration: {} seconds\n".format(int(self.monitor.status_duration[state].total_seconds()))
+
+ bot.send_message(config.TELEGRAM_GROUP, response).wait()
+
+ if updates[0].message.text.startswith('/reboot'):
+ os.system(config.TELEGRAM_REBOOT_COMMAND)
+ bot.send_message(config.TELEGRAM_GROUP, '\xe2\x84\xb9 I issued a reboot command. I hope everything is ok.').wait()
+ except:
+ pass
+
+ new_alarms = self.monitor.alarms()
+
+ for alarm in new_alarms:
+ if alarm not in alarms:
+ bot.send_message(config.TELEGRAM_GROUP, '\xe2\x9a\xa0 Problem \xe2\x9a\xa0\nSorry to bother you, but I think there is a problem with the glutt-o-matique: \n\n{}'.format(alarm)).wait()
+
+ for old_alarm in alarms:
+ if old_alarm not in new_alarms:
+ bot.send_message(config.TELEGRAM_GROUP, '\xe2\x9c\x85 Problem fixed \xe2\x9c\x85\nThe following problem is not anymore a problem with the glutt-o-matique:\n\n{}'.format(alarm)).wait()
+
+ alarms = new_alarms
+
+ time.sleep(1)
diff --git a/config.py.dist b/config.py.dist
index 8edb5d8..0e27155 100644
--- a/config.py.dist
+++ b/config.py.dist
@@ -2,3 +2,7 @@ SERIALPORT = "/dev/ttyUSB0"
BAUDRATE = 9600
LINES_TO_KEEP = 200
LAST_LINE_TO_KEEP = 1000
+
+TELEGRAM_API_TOKEN = ''
+TELEGRAM_GROUP = ''
+TELEGRAM_REBOOT_COMMAND = './reboot.sh'
diff --git a/glutte_serial_web.py b/glutte_serial_web.py
index 72bc6e4..9966646 100755
--- a/glutte_serial_web.py
+++ b/glutte_serial_web.py
@@ -28,11 +28,13 @@ from time import sleep
from flask import Flask, render_template
from flask_sockets import Sockets
import serialrx
+import adsl
app = Flask(__name__)
sockets = Sockets(app)
ser = serialrx.SerialRX()
+adsl = adsl.ADSL(ser)
@app.route('/')
@@ -66,6 +68,7 @@ def stream(socket):
ser.unregister_client(queue)
ser.start()
+adsl.start()
if __name__ == "__main__":
print("You're running in dev mode, only one client at a time will works ! Please use gunicorn to fix this :)")
diff --git a/reboot.sh b/reboot.sh
new file mode 100755
index 0000000..e606947
--- /dev/null
+++ b/reboot.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+sudo /usr/bin/openocd -f /usr/share/openocd/scripts/board/stm32f4discovery.cfg -c "init" -c "reset" -c "exit"
diff --git a/requirements.txt b/requirements.txt
index e9ee31f..925dfbf 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,3 +9,4 @@ pyserial==3.1.1
Werkzeug==0.11.11
Flask-Sockets==0.2.1
gunicorn==19.6.0
+twx.botapi==2.1.0