Table of Contents
Hardware Status
Normal screen is currently out of action gubbed. Tim recommends checking caps however not enough time was available on the day of discovering the screen being out. A temporary screen has been put in place to allow for interim IRC usage.
Project Background
Rob wanted a way to promote IRC use and make it feel more part of the lab rather than a separate 'IRC club', and also open it up to non-IRC users and provide a way to quickly reply. Similar IRC terminals exist at other hackerspaces, such as Helsinki Hacklab.
Main Hardware Components
- Raspberry Pi A+ & 3D printed case
- Some crappy 'PiHut' rt2800-based wifi dongle
- Optiquest Q22wb (Viewsonic/BENQ) 22“ 1680×1050 (16:10) TFT mounted vertically, provided by shabble
- Wall mount VESA arm
- Also a passive USB 2.0 hub and a small USB keyboard
Piecing it together
The Pi is back-powered via the hub, which is in turn back-powered via a small in-line 5v 1A PSU originally for a Zip drive. There are a few of these useful PSUs in use in the lab. The back-powering is a result of only wanting to use bits in the 'cables for butchering' box.
Pi, USB hub, and PSU are velcro'd on to the back of the monitor. The monitor is mounted on the wall using a wall bracket salvaged from a smashed TV that was being thrown out. The wall bracket is capable of a wide range of movement.
The keyboard is bodged in place using lots of hot glue and some L brackets which are stuffed behind the conduit. Seems solid for now.
Wifi
Terminal is connected to the main 'Hacklab' network. Wifi was showing to be very unreliable in 'n' mode. Having forced an arbitrary speed of 22Mbit/s, the wifi is now stable. Other Pis using similar dongles have experienced high latency and loss too. The problem doesn't exist when connected to different access points.
The following script has been added:
/etc/network/if-up.d/iwconfig
#!bin/sh iwconfig wlan0 rate 22 fixed
The following has also been observed from time to time in the logs (syslog, dmesg):
[37316.894424] ieee80211 phy0: rt2800usb_entry_txstatus_timeout: Warning - TX status timeout for entry 15 in queue 2 [37317.005566] ieee80211 phy0: rt2800usb_txdone: Warning - Got TX status for an empty queue 2, dropping
Automatically reconnecting wifi
/etc/rc.local:
/root/wifimonitor 2>&1 &
/root/wifimonitor:
#!/bin/bash while true ; do if ifconfig wlan0 | grep -q "inet addr:" ; then sleep 60 else ifdown wlan0 sleep 10 ifup --force wlan0 sleep 10 fi done
OS Config
Stock Raspbian with all x11-* and various other things removed.
/etc/inittab modified to replace tty1 with IRC:
1:2345:once:/root/irssi 2:23:respawn:/sbin/getty 38400 tty2 3:23:respawn:/sbin/getty 38400 tty3 4:23:respawn:/sbin/getty 38400 tty4 5:23:respawn:/sbin/getty 38400 tty5 6:23:respawn:/sbin/getty 38400 tty6
/root/irssi:
#!bin/bash screen -S IRC su - --command "irssi" -l pi
It's run a screen session to allow easy remote irssi maintaining via screen -x.
The console font has been changed using:
sudo dpkg-reconfigure console-setup
Terminus font in UTF8, at size 16×32.
Powering on/off the screen automatically
The screen turns off when the lab is empty and turns back on again as soon as someone enters the lab and triggers the PIR. This happens via the message bus and is handled by idle.py which is currently run from rc.local. idle.py was written by Tim initially.
/etc/rc.local:
/home/pi/idle.py > /dev/null 2>&1 &
/home/pi/idle.py:
#!/usr/bin/env python import paho.mqtt.client as mqtt import subprocess last_state = None def on_connect(client, userdata, flags, rc): client.subscribe("sensor/global/presence") def on_message(client, userdata, msg): global last_state # ignore retained (non-realtime) messages #if msg.retain: # return if last_state != msg.payload: # state has changed if msg.payload == "active": # screen on subprocess.call("tvservice -p", shell=True) elif msg.payload == "empty": # screen off subprocess.call("tvservice -o", shell=True) last_state = msg.payload m = mqtt.Client() m.on_connect = on_connect m.on_message = on_message m.connect("mqtt") m.loop_forever()
Required to run:
apt-get install python-pip pip install paho-mqtt
Log file of TV status (due to people wondering if it doesn't actually ever turn off):
~/idle.log
Irssi config
Summary:
- Auto connect to Libera
- NickServ identification
- Main channel window with only PUBLICS, ACTIONS and NICKS.
- Small split window at the top with everything else including server messages and channel join/parts and quits.
- Highlight triggers ICQ 'uhoh' to be played.
servers = ( { address = "irc.libera.chat"; chatnet = "libera"; port = "6697"; use_ssl = "yes"; ssl_verify = "yes"; autoconnect = "yes"; } ); chatnets = { libera = { type = "IRC"; autosendcmd = "/^msg nickserv identify <PASSWORD>;/^win 2"; }; }; channels = ( { name = "#irssi"; chatnet = "ircnet"; autojoin = "No"; }, { name = "silc"; chatnet = "silc"; autojoin = "No"; }, { name = "#edinhacklab"; chatnet = "libera"; autojoin = "yes"; } ); aliases = { J = "join"; WJOIN = "join -window"; WQUERY = "query -window"; LEAVE = "part"; BYE = "quit"; EXIT = "quit"; SIGNOFF = "quit"; DESCRIBE = "action"; DATE = "time"; HOST = "userhost"; LAST = "lastlog"; SAY = "msg *"; WI = "whois"; WII = "whois $0 $0"; WW = "whowas"; W = "who"; N = "names"; M = "msg"; T = "topic"; C = "clear"; CL = "clear"; K = "kick"; KB = "kickban"; KN = "knockout"; BANS = "ban"; B = "ban"; MUB = "unban *"; UB = "unban"; IG = "ignore"; UNIG = "unignore"; SB = "scrollback"; UMODE = "mode $N"; WC = "window close"; WN = "window new hide"; SV = "say Irssi $J ($V) - http://irssi.org/"; GOTO = "sb goto"; CHAT = "dcc chat"; RUN = "SCRIPT LOAD"; CALC = "exec - if command -v bc >/dev/null 2>&1\\; then printf '%s=' '$*'\\; echo '$*' | bc -l\\; else echo bc was not found\\; fi"; SBAR = "STATUSBAR"; INVITELIST = "mode $C +I"; Q = "QUERY"; "MANUAL-WINDOWS" = "set use_status_window off;set autocreate_windows off;set autocreate_query_level none;set autoclose_windows off;set reuse_unused_windows on;save"; EXEMPTLIST = "mode $C +e"; ATAG = "WINDOW SERVER"; UNSET = "set -clear"; RESET = "set -default"; }; statusbar = { # formats: # when using {templates}, the template is shown only if it's argument isn't # empty unless no argument is given. for example {sb} is printed always, # but {sb $T} is printed only if $T isn't empty. items = { # start/end text in statusbars barstart = "{sbstart}"; barend = "{sbend}"; topicbarstart = "{topicsbstart}"; topicbarend = "{topicsbend}"; # treated "normally", you could change the time/user name to whatever time = "{sb $Z}"; user = "{sb {sbnickmode $cumode}$N{sbmode $usermode}{sbaway $A}}"; # treated specially .. window is printed with non-empty windows, # window_empty is printed with empty windows window = "{sb $winref:$tag/$itemname{sbmode $M}}"; window_empty = "{sb $winref{sbservertag $tag}}"; prompt = "{prompt $[.15]itemname}"; prompt_empty = "{prompt $winname}"; topic = " $topic"; topic_empty = " Irssi v$J - http://www.irssi.org"; # all of these treated specially, they're only displayed when needed lag = "{sb Lag: $0-}"; act = "{sb Act: $0-}"; more = "-- more --"; }; # there's two type of statusbars. root statusbars are either at the top # of the screen or at the bottom of the screen. window statusbars are at # the top/bottom of each split window in screen. default = { # the "default statusbar" to be displayed at the bottom of the window. # contains all the normal items. window = { disabled = "no"; # window, root type = "window"; # top, bottom placement = "bottom"; # number position = "1"; # active, inactive, always visible = "active"; # list of items in statusbar in the display order items = { barstart = { priority = "100"; }; time = { }; user = { }; window = { }; window_empty = { }; lag = { priority = "-1"; }; act = { priority = "10"; }; more = { priority = "-1"; alignment = "right"; }; barend = { priority = "100"; alignment = "right"; }; }; }; # statusbar to use in inactive split windows window_inact = { type = "window"; placement = "bottom"; position = "1"; visible = "inactive"; items = { barstart = { priority = "100"; }; window = { }; window_empty = { }; more = { priority = "-1"; alignment = "right"; }; barend = { priority = "100"; alignment = "right"; }; }; }; # we treat input line as yet another statusbar :) It's possible to # add other items before or after the input line item. prompt = { type = "root"; placement = "bottom"; # we want to be at the bottom always position = "100"; visible = "always"; items = { prompt = { priority = "-1"; }; prompt_empty = { priority = "-1"; }; # treated specially, this is the real input line. input = { priority = "10"; }; }; }; # topicbar topic = { type = "root"; placement = "top"; position = "1"; visible = "always"; items = { topicbarstart = { priority = "100"; }; topic = { }; topic_empty = { }; topicbarend = { priority = "100"; alignment = "right"; }; }; }; }; }; settings = { core = { real_name = "Edinburgh Hacklab"; user_name = "ircpi"; nick = "hacklab-"; }; "fe-text" = { actlist_sort = "refnum"; }; "fe-common/core" = { window_check_level_first = "yes"; window_default_level = "-ALL PUBLIC ACTIONS NICKS"; beep_when_window_active = "yes"; beep_when_away = "yes"; beep_msg_level = "HILIGHT"; bell_beeps = "yes"; }; "perl/core/scripts" = { beep_cmd = "/srv/hacksense/bin/request-soundfile uhoh.mp3 &"; }; }; hilights = ( { text = "hacklab-"; nick = "yes"; word = "yes"; } ); windows = { 1 = { immortal = "yes"; name = "(status)"; level = "CRAP MSGS NOTICES SNOTES CTCPS JOINS PARTS QUITS KICKS MODES TOPICS WALLOPS INVITES DCC DCCMSGS CLIENTNOTICES CLIENTCRAP CLIENTERRORS HILIGHTS"; sticky = "yes"; }; 2 = { level = "PUBLICS ACTIONS NICKS"; items = ( { type = "CHANNEL"; chat_type = "IRC"; name = "#edinhacklab"; tag = "libera"; } ); }; }; mainwindows = { 2 = { first_line = "8"; lines = "43"; }; 1 = { first_line = "1"; lines = "7"; }; };
There are two plugins in use. nickcolor.pl and beep_beep.pl. Both are unmodified.
Playing the sound
Part of the 'hacksense' stuff has been copied over:
- /srv/hacksense/bin/request-soundfile
- uhoh.mp3 is on doorbot which has the speaker attached to it.
In irssi config: beep_cmd = ”/srv/hacksense/bin/request-soundfile uhoh.mp3 &“