Commit dffa05ee authored by hackEns's avatar hackEns
Browse files

Big update

parent a62d13fa
config.py
data/history
startup.sh
start_ssh.sh
data/
__pycache__
*.pyc
*~
......
Jarvis
======
hackEns multifunction bot
Requirements
------------
* Python 3
* oggfwd
* python-mysql-connector
* requests
* TODO
Installation
------------
Copy `config.py.example` to `config.py` and then edit it.
`config.py` should contain the following items:
* server = "server"
* channel = "channel"
* botnick = "botnick"
* password = "pass"
Run `jarvis_bot.py`
# TODO
Coding Style
------------
TODO
----
Add comments.
Jarvis
======
hackEns multifunction bot to handle most of our internal management.
## Installation
Jarvis can be easily installed on a Raspberry Pi, starting from an up-to-date Raspbian image.
1. Download and put the latest Raspbian image on a SD card.
2. Start the Raspberry Pi. Set it correctly running `sudo raspi-config` (enable camera and so on).
3. Clone Jarvis repo.
4. Run the scripts in `system/` folder to install the requirements.
5. Copy `config.py.example` to `config.py` and then edit it. All items should be self-explicit.
6. Make sure your user is member of the `gpio` and `video` groups.
7. Jarvis does not automatically export the GPIO pins to prevent it from running as `root`. So you should `gpio export PIN out` for the pins you use (1 and 7 by defautl).
7. Run `jarvis_bot.py` to start Jarvis.
*Note :* Jarvis requires a MySQL database to be used, and a webserver to serve the web visualisation (repo [Jarvis web](https://github.com/hackEns/Jarvis_web)). As our webserver does not run on the Raspberry Pi, the above scripts do not include the setup for the webserver and the MySQL database. You should install and set them yourself.
## Files and folders
* `arduino/`
* This folder contains some example arduino scripts to use an Arduino and a regular PC instead of the Raspberry Pi GPIO pins. They are just here for demo purpose and are no longer used. Thus, they may be unstable.
* `aziz.py` is our moderation script, to inform us of new emails waiting for moderation. It's basically a Jarvis plugin.
* `data` folder contains the scripts, aliases etc you put into Jarvis.
* `jarvis.all.log` (created by Jarvis) is the complete log of the watched channel.
* `jarvis_bot.py` is the main script, which serves the bot.
* `jarvis_cmd.py` is a collection of functions to translate Jarvis actions to GPIO actions etc.
* `jarvis.sql` is a SQL file which will allow you to create the necessary tables for Jarvis.
* `Rules` contains a set of scripts for the various Jarvis actions.
* `stream.py` is the script used to handle the cam streaming.
* `STL export` contains 3D models for our setup.
* `updater.sh` is a bash script called to update jarvis.
......@@ -12,7 +12,8 @@ class Dis(Rule):
"""Say something"""
if len(args) > 1:
for something in args[1:]:
if self.cmd.dis(something):
returncode = self.cmd.dis(something)
if returncode is not False and returncode == 0:
self.bot.ans(serv, author, something)
else:
self.bot.ans(serv, author, "Je n'arrive plus à parler…")
......
# TODO
* logs => tags, mettre dans shaarli ?
* pygst
* Jasper ?
# À tester
* update
* notifs emprunts
* modération
Files kept for information.
Jarvis can run using a normal computer and Arduinos to perform actions. In this case, use the codes in this folder.
# IRC parameters
server = ""
port = 6667
use_ssl = False
channel = ""
nick = "jarvis"
desc = "Jarvis, au rapport !"
......@@ -32,13 +33,10 @@ stream_url = ""
stream_genre = ""
oggfwd_path = ""
# Controller : "raspi" or "arduino". Specify wether everything is on the raspi or if there is an external micro-controller.
controller = "raspi"
# Arduino parameters
cam_path = "/dev/ttyACM0"
atx_path = cam_path
lum_path = "/dev/ttyUSB0"
# Pins
# Uses BCM numbering
pin_cam = 18
pin_atx = 4
# Access control
authorized = []
......
......@@ -50,16 +50,6 @@ CREATE TABLE IF NOT EXISTS `budget` (
`budget` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
--
-- Dumping data for table `budget`
--
INSERT INTO `budget` (`id`, `amount`, `author`, `date`, `comment`, `budget`) VALUES
(1, 200, 'test', '2014-06-22 17:35:05', 'testbidule', ''),
(2, -100, 'test', '2014-06-21 17:35:05', 'testbidule', '');
-- --------------------------------------------------------
--
-- Table structure for table `shopping`
--
......@@ -73,15 +63,6 @@ CREATE TABLE IF NOT EXISTS `shopping` (
`bought` tinyint(4) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
--
-- Dumping data for table `shopping`
--
INSERT INTO `shopping` (`id`, `item`, `author`, `comment`, `date`, `bought`) VALUES
(1, 'test', 'bidule', 'Je propose d''acheter chose.', '2014-06-22 19:40:56', 0),
(2, 'test', 'bidule', 'Je propose d''acheter chose2.', '2014-06-22 19:41:04', 1);
--
-- Indexes for dumped tables
--
......
......@@ -9,6 +9,7 @@ import config
import datetime
from email.mime.text import MIMEText
import irc.bot as ircbot
import irc.connection
import jarvis_cmd
import mysql.connector
import os
......@@ -17,6 +18,7 @@ import re
import requests
import shlex
import smtplib
import ssl
import subprocess
import sys
......@@ -25,10 +27,18 @@ from Rules import *
class JarvisBot(ircbot.SingleServerIRCBot):
def __init__(self):
ircbot.SingleServerIRCBot.__init__(self, [(config.server,
config.port)],
config.nick,
config.desc)
if not config.use_ssl:
ircbot.SingleServerIRCBot.__init__(self, [(config.server,
config.port)],
config.nick,
config.desc)
else:
self.ssl_factory = ssl_factory = irc.connection.Factory(wrapper=ssl.wrap_socket)
ircbot.SingleServerIRCBot.__init__(self, [(config.server,
config.port)],
config.nick,
config.desc,
connect_factory=self.ssl_factory)
self.version_nb = "0.2"
self.error = None
self.basepath = os.path.dirname(os.path.realpath(__file__))+"/"
......@@ -39,6 +49,8 @@ class JarvisBot(ircbot.SingleServerIRCBot):
self.bdd = mysql.connector.connect(**config.mysql)
self.bdd_cursor = self.bdd.cursor()
except mysql.connector.Error as err:
if config.debug:
print("Debug : " + str(err))
if err.errno == mysql.connector.errorcode.ER_ACCESS_DENIED_ERROR:
self.error = "Accès refusé à la BDD."
elif err.errno == mysql.connector.errorcode.ER_BAD_DB_ERROR:
......@@ -70,14 +82,14 @@ class JarvisBot(ircbot.SingleServerIRCBot):
help_msg="atx on|off")
self.add_rule("budget",
self.budget,
help_msg="budget (ajoute|retire) [dépense|crédit] "+
help_msg="budget (ajoute|retire) [dépense|crédit] " +
"montant [budget=BUDGET] commentaire")
self.add_rule("camera",
self.camera,
help_msg="camera ALIAS|ANGLE")
self.add_rule("courses",
self.courses,
help_msg="courses (acheter|annuler|acheté) item [comment]")
help_msg="courses (acheter|annuler|acheté) item [commentaire]")
self.add_rule("dis",
self.dis,
help_msg="dis \"quelque chose\"")
......@@ -89,7 +101,7 @@ class JarvisBot(ircbot.SingleServerIRCBot):
help_msg="emprunt outil \"jj/mm hh\" [email]")
self.add_rule("historique",
self.historique,
help_msg="historique nb_lignes|(start end)")
help_msg="historique nb_lignes|(début fin)")
self.add_rule("info",
self.info,
help_msg="info [atx|camera|leds|stream]")
......@@ -99,10 +111,10 @@ class JarvisBot(ircbot.SingleServerIRCBot):
self.add_rule("lien",
self.lien,
help_msg=("lien (dernier | " +
"(supprime|cache|affiche) [id|permalien]"))
"(supprime|cache|affiche) [id|permalien])"))
self.add_rule("log",
self.log,
help_msg="log debut ... fin")
help_msg="log début ... fin")
self.add_rule("lumiere",
self.lumiere,
help_msg="lumiere (R G B)|script")
......@@ -179,6 +191,8 @@ class JarvisBot(ircbot.SingleServerIRCBot):
try:
self.rules[msg[0]]['action'](serv, author, msg)
except InvalidArgs:
if config.debug:
print("Debug : " + str(msg))
self.aide(serv, author, msg)
else:
self.ans(serv, author, "Je n'ai pas compris…")
......@@ -191,6 +205,8 @@ class JarvisBot(ircbot.SingleServerIRCBot):
try:
self.rules[msg[0]]['action'](serv, author, msg)
except InvalidArgs:
if config.debug:
print("Debug : " + str(msg))
self.aide(serv, author, msg)
self.log.add_cache(author, raw_msg) # Log each line
......@@ -199,7 +215,7 @@ class JarvisBot(ircbot.SingleServerIRCBot):
for url in set(urls):
if url.startswith(config.shaarli_url):
continue
base_params = (("do", "api"), ("token", config.shaarli_key))
base_params = (("do", "api"), ("token", config.shaarli_token))
r = requests.get(config.shaarli_url,
params=base_params + (("url", url),))
if r.text != "" and len(r.json()) > 0:
......@@ -267,6 +283,8 @@ class JarvisBot(ircbot.SingleServerIRCBot):
amount = -amount
first_index = 4
except (KeyError, ValueError):
if config.debug:
print("Debug : " + str(args))
raise InvalidArgs
try:
comment = args[first_index:]
......@@ -279,6 +297,10 @@ class JarvisBot(ircbot.SingleServerIRCBot):
except KeyError:
comment = ""
budget = ""
if budget == "":
# If no budget specified, put it in current year
year = datetime.datetime.now().year
budget = str(year) + " / " + str(year + 1)
if args[1] == "ajoute":
if comment == "":
raise InvalidArgs
......@@ -289,11 +311,15 @@ class JarvisBot(ircbot.SingleServerIRCBot):
assert(self.bdd_cursor is not None)
self.bdd_cursor.execute(query, values)
except AssertionError:
if config.debug:
print("Debug : Database disconnected.")
self.ans(serv, author,
"Impossible d'ajouter la facture, base de données " +
"injoignable.")
return
except mysql.connector.errors.Error as err:
if config.debug:
print("Debug : " + str(err))
self.ans(serv,
author,
"Impossible d'ajouter la facture. (%s)" % (err,))
......@@ -325,11 +351,15 @@ class JarvisBot(ircbot.SingleServerIRCBot):
"comment LIKE %s")
self.bdd_cursor.execute(query, values)
except AssertionError:
if config.debug:
print("Debug : Database disconnected.")
self.ans(serv, author,
"Impossible de supprimer la facture, base de données " +
"injoignable.")
return
except mysql.connector.errors.Error as err:
if config.debug:
print("Debug : " + str(err))
self.ans(serv,
author,
"Impossible de supprimer la facture. (%s)" % (err,))
......@@ -362,18 +392,22 @@ class JarvisBot(ircbot.SingleServerIRCBot):
values = (args[2], author, comment, datetime.datetime.now())
self.bdd_cursor.execute(query, values)
except AssertionError:
if config.debug:
print("Debug : Database disconnected")
self.ans(serv, author,
"Impossible d'ajouter l'objet à la liste de courses, " +
"base de données injoignable.")
return
except mysql.connector.errors.Error as err:
if config.debug:
print("Debug : " + str(err))
self.ans(serv,
author,
"Impossible d'ajouter l'objet à la liste de courses. (%s)" % (err,))
return
self.ans(serv, author, "Item ajouté à la liste de courses.")
elif args[1] == "annuler":
query = ("SELECT COUNT(*) as nb FROM shopping WHERE item=%s AND "+
query = ("SELECT COUNT(*) as nb FROM shopping WHERE item=%s AND " +
"comment LIKE %s")
values = (args[2], '%'+comment+'%')
try:
......@@ -389,11 +423,15 @@ class JarvisBot(ircbot.SingleServerIRCBot):
"comment LIKE %s")
self.bdd_cursor.execute(query, values)
except AssertionError:
if config.debug:
print("Debug : Database disconnected")
self.ans(serv, author,
"Impossible de supprimer l'item, base de données " +
"injoignable.")
return
except mysql.connector.errors.Error as err:
if config.debug:
print("Debug : " + str(err))
self.ans(serv,
author,
"Impossible de supprimer l'item. (%s)" % (err,))
......@@ -416,11 +454,15 @@ class JarvisBot(ircbot.SingleServerIRCBot):
"comment LIKE %s AND bought=0")
self.bdd_cursor.execute(query, values)
except AssertionError:
if config.debug:
print("Debug : Database disconnected")
self.ans(serv, author,
"Impossible de marquer l'item comme acheté, " +
"base de données injoignable.")
return
except mysql.connector.errors.Error as err:
if config.debug:
print("Debug : " + str(err))
self.ans(serv,
author,
"Impossible de marquer l'item comme acheté. (%s)" % (err,))
......@@ -455,6 +497,8 @@ class JarvisBot(ircbot.SingleServerIRCBot):
else:
self.ans(serv, author, "Impossible de régler les LEDs.")
except (AssertionError, ValueError):
if config.debug:
print("Debug : " + str(msg))
raise InvalidArgs
elif len(args) == 2:
script = os.path.join(self.basepath+"data/leds", args[1])+".py"
......@@ -509,6 +553,8 @@ class JarvisBot(ircbot.SingleServerIRCBot):
def stream(self, serv, author, args):
"""Handles stream transmission"""
args = [i.lower() for i in args]
if len(args) < 2:
raise InvalidArgs
if args[1] == "on":
if self.oggfwd is not None and self.streamh is not None:
self.ans(serv, author,
......@@ -578,11 +624,15 @@ class JarvisBot(ircbot.SingleServerIRCBot):
assert(self.bdd_cursor is not None)
self.bdd_cursor.execute(query, values)
except AssertionError:
if config.debug:
print("Debug : Database disconnected")
self.ans(serv, author,
"Impossible de rendre l'outil, " +
"base de données injoignable.")
return
except mysql.connector.errors.Error as err:
if config.debug:
print("Debug : " + str(err))
self.ans(serv,
author,
"Impossible de rendre l'objet. (%s)" % (err,))
......@@ -602,11 +652,15 @@ class JarvisBot(ircbot.SingleServerIRCBot):
assert(self.bdd_cursor is not None)
self.bdd_cursor.execute(query, values)
except AssertionError:
if config.debug:
print("Debug : Database disconnected")
self.ans(serv, author,
"Impossible de rendre l'outil, " +
"base de données injoignable.")
return
except mysql.connector.errors.Error as err:
if config.debug:
print("Debug : " + str(err))
self.ans(serv,
author,
"Impossible de rendre l'objet. (%s)" % (err,))
......@@ -629,8 +683,16 @@ class JarvisBot(ircbot.SingleServerIRCBot):
assert(self.bdd_cursor is not None)
self.bdd_cursor.execute(query,
(now + delta, delta, now))
except (AssertionError, mysql.connector.errors.Error):
serv.say(serv,
except AssertionError:
if config.debug:
print("Debug : Database disconnected")
self.say(serv,
"Impossible de récupérer les notifications d'emprunts.")
return
except mysql.connector.errors.Error as err:
if config.debug:
print("Debug : " + str(err))
self.say(serv,
"Impossible de récupérer les notifications d'emprunts.")
return
for (id_field, borrower, tool, from_field, until) in self.bdd_cursor:
......@@ -659,7 +721,7 @@ class JarvisBot(ircbot.SingleServerIRCBot):
def lien(self, serv, author, args):
"""Handles links managements through Shaarli API"""
base_params = (("do", "api"), ("token", config.shaarli_key))
base_params = (("do", "api"), ("token", config.shaarli_token))
args[1] = args[1].lower()
if len(args) > 1 and args[1] == "dernier":
self.ans(serv, author, self.last_added_link)
......
......@@ -8,7 +8,7 @@ import struct
import subprocess
import time
wiringpi2.wiringPiSetup()
wiringpi2.wiringPiSetupSys()
def send(ser, mode, msg): # TO REMOVE
......@@ -27,8 +27,8 @@ def camera(angle):
return False
towrite = int(127+int(127*float(angle)/180))
wiringpi2.pinMode(1, wiringpi2.PWM_OUTPUT)
wiringpi2.pwmWrite(1, towrite)
#wiringpi2.pinMode(PIN_CAM, wiringpi2.PWM_OUTPUT)
wiringpi2.pwmWrite(jarvis.pin_cam, towrite)
time.sleep(0.100)
......@@ -48,12 +48,11 @@ def lumiere(r, v, b):
def atx(etat):
PIN_ATX = 7
PIN2_ATX = 8
wiringpi2.pinMode(PIN_ATX, 1)
wiringpi2.pinMode(PIN2_ATX, 1)
wiringpi2.digitalWrite(PIN_ATX, etat)
wiringpi2.digitalWrite(PIN2_ATX, etat)
#wiringpi2.pinMode(PIN_ATX, 1)
wiringpi2.digitalWrite(config.pin_atx, etat)
def atx_status():
return wiringpi2.digitalRead(config.pin_atx_status)
def dis(something):
......
#!/usr/bin/sh
until ping -c 4 hackens.org > /dev/null 2>&1; do
sleep 2
done
screen -dmS jarvis && screen -S jarvis -p 0 -X stuff "~/Jarvis/jarvis_bot.py$(printf \\r)"
#!/usr/bin/env python
#!/usr/bin/env python2
# From https://github.com/iXce/Printrun_stream
"""
......@@ -7,11 +7,12 @@ Script to handle the webcam streaming.
import os, sys
import xmlrpc.client as xmlrpcclient
#import xmlrpc.client as xmlrpcclient
import xmlrpclib
import threading
import datetime
rpc = xmlrpcclient.ServerProxy('http://localhost:7978')
rpc = xmlrpclib.ServerProxy('http://localhost:7978')
import io
import matplotlib as mpl
......
#!/usr/bin/env python
# -*- coding: utf8 -*-
import os
import sys
import serial
path = "/dev/ttyACM1"
angle = int(sys.argv[1])
if angle < 0 or angle > 180:
print "Angle invalide"
raise SystemExit
os.system("stty -hup -F "+path)
try:
ser = serial.Serial(path, 115200)
except:
sys.exit("Erreur à l'ouverture du port série.")
towrite = chr(127+int(127*float(angle)/180))
ser.readline()
ser.write(towrite)
ser.flush()
print ser.readline().strip()
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment