Compare commits

...

13 Commits
v0.1 ... master

14 changed files with 330 additions and 143 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
__pycache__

13
License
View File

@ -1,13 +0,0 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

View File

@ -1,18 +1,26 @@
# Eingangsschalter # Dependencies
der Hebel bei der Eingangstür, der im IRC schreibt, wenn jemand den Hebel zieht.
das python-skript legt man idealerweise in /usr/bin/ - python3
- nginx
- sopel
das systemd-ding legt man am besten in /etc/systemd/system/
mit den systemctl-befehlen muss man die "unit" dann noch starten. ## Install
further reading / sources : ```
cd ~/Eingangsschalter
sudo ./install.sh
```
https://linuxacademy.com/blog/geek/creating-an-irc-bot-with-python3/ ### Afterwards
- configurate nginx
- configurate sopel
- edit ~/.sopel/default.cfg
- restart ircbot with `sudo systemctl restart ircbot` or run `sudo ./install.sh` again
http://pi4j.com/pins/model-b-rev1.html ## Update
```
http://razzpisampler.oreilly.com/ch07.html cd ~/Eingangsschalter
git pull
http://wiringpi.com/the-gpio-utility/ sudo ./install.sh
```

25
install.sh Executable file
View File

@ -0,0 +1,25 @@
#!/bin/sh
INSTALL_PATH=$PWD
# install dependencies
# apt-get install sopel nginx certbot
# install json (to save)
cp $INSTALL_PATH/spaceapi.json /var/www/html/spaceapi.json
chown pi:pi /var/www/html/spaceapi.json
# install mini-website
cp $INSTALL_PATH/www/index.html /var/www/html/index.html
# install ircbot
ln -s $INSTALL_PATH/sopel-bot/modules /home/pi/.sopel
if [ ! -f /home/pi/.sopel/default.cfg ]; then
cp $INSTALL_PATH/sopel-bot/default.cfg /home/pi/.sopel/
fi
#install services
cp $INSTALL_PATH/systemd/schalter.service /etc/systemd/system
cp $INSTALL_PATH/systemd/ircbot.service /etc/systemd/system
systemctl daemon-reload
systemctl enable ircbot schalter
systemctl start ircbot schalter

View File

@ -1,11 +0,0 @@
[Unit]
Description=irc-daemon für türschalter
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/ircbot.py
[Install]
WantedBy=multi-user.target

View File

@ -1,85 +0,0 @@
#!/usr/bin/python
import socket
import RPi.GPIO as GPIO
import time
ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server = "irc.freenode.net" # Server
channel = "#yanniktest" # Channel
botnick = "yanniksBot" # Your bots nick
adminname = "yannik_" #Your IRC nickname.
exitcode = "bye " + botnick
ircsock.connect((server, 6667)) # Here we connect to the server using the port 6667
ircsock.send(bytes("USER "+ botnick +" "+ botnick +" "+ botnick + " " + botnick + "\n", "UTF-8")) #We are basically filling out a form with this line and saying to set all the fields to the bot nickname.
ircsock.send(bytes("NICK "+ botnick +"\n", "UTF-8")) # assign the nick to the bot
def joinchan(chan): # join channel(s).
ircsock.send(bytes("JOIN "+ chan +"\n", "UTF-8"))
ircmsg = "hey, ircmsg!"
while ircmsg.find("End of /NAMES list.") == -1:
ircmsg = ircsock.recv(2048).decode("UTF-8")
ircmsg = ircmsg.strip('\n\r')
print(ircmsg)
def ping(): # respond to server Pings.
ircsock.send(bytes("PONG :pingis\n", "UTF-8"))
def sendmsg(msg, target=channel): # sends messages to the target.
ircsock.send(bytes("PRIVMSG "+ target +" :"+ msg +"\n", "UTF-8"))
def main():
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
joinchan(channel)
prev=None
while 1:
#print("ein weiterer durchlauf der main-schleiffe")
current=GPIO.input(18)
# liste[i%2] = GPIO.input(18)
if ( current != prev) :
if( prev != None):
sendmsg("schalter wurde betätigt! {}".format(current))
if (current == 0):
sendmsg("es ist nun offen!")
if (current == 1):
sendmsg("es ist nun zu, gute nacht!")
prev=current
ircmsg=" "
time.sleep(10)
#ircmsg = ircsock.recv(2048).decode("UTF-8")
#ircmsg = ircmsg.strip('\n\r')
print(ircmsg)
if ircmsg.find("PRIVMSG") != -1:
name = ircmsg.split('!',1)[0][1:]
message = ircmsg.split('PRIVMSG',1)[1].split(':',1)[1]
if len(name) < 17:
if message.find('Hi ' + botnick) != -1:
sendmsg("Hello " + name + "!")
if message[:5].find('.tell') != -1:
target = message.split(' ', 1)[1]
if target.find(' ') != -1:
message = target.split(' ', 1)[1]
target = target.split(' ')[0]
else:
target = name
message = "Could not parse. The message should be in the format of .tell [target] [message] to work properly."
sendmsg(message, target)
if name.lower() == adminname.lower() and message.rstrip() == exitcode:
sendmsg("oh...okay. :'(")
ircsock.send(bytes("QUIT \n", "UTF-8"))
return
else:
if ircmsg.find("PING :") != -1:
ping()
main()

View File

@ -1,22 +0,0 @@
import json
import time
import RPi.GPIO as GPIO
pin_number = 18;
data = {1:"asdf"}
wert_des_schalters = False
while True:
#/* Sphinx Vorschlag */
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
while True:
time.sleep(1)
if wert_des_schalters != GPIO.input(18) : # das ist gut
time.sleep(1) # // Contact bounce protection
print("wert wurde geaendert")
wert_des_schalters = GPIO.input(pin_number)
data = {1:wert_des_schalters}
with open('data.txt', 'w') as outfile:
json.dump(data, outfile)

63
schalter.py Executable file
View File

@ -0,0 +1,63 @@
#!/usr/bin/env python3
#########################################################################
# Spaceapi Implementation for a 63A switch
# (using 5 V 150 mA Raspberry Pi GPIO pin)
#
#
#########################################################################
# to make sure that everything does not happen at once
import time
# json and raspi imports
import json
# for using GPIO pins of the raspi
import RPi.GPIO as GPIO
# for logging
import logging
from systemd import journal
########################################################
#start init
journal.write("CCCHB space api switch v. 0.3")
currentState = False
#################################################################################
#function definitons:
#################################################################################
# will read the GPIO header of the pi and write the current state in the www spaceapi json file
def switched(pos):
global currentState
wert_des_schalters = not bool(GPIO.input(pin_number))
if pos != wert_des_schalters:
journal.write("state changed to: %s " %wert_des_schalters)
chn_time = time.time()
icons = data.get("state").get('icon')
data.update({'state':{'open':wert_des_schalters,'lastchange':chn_time, "icon":icons}})
currentState = wert_des_schalters
with open('/var/www/html/spaceapi.json', 'w') as outfile:
json.dump(data, outfile,sort_keys=True)
#################################################################################
#init GPIO pin on raspi
pin_number = 18; #set GPIO Pin number
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin_number, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(pin_number, GPIO.BOTH, callback=switched, bouncetime=600)
journal.write("init complete... starting json foo")
#read json file
with open('spaceapi.json','r') as infile:
data = json.load(infile)
#run switched once to get current switch status and change if needed.
#switched(wert_des_schalters)
try:
while True:
time.sleep(5)
switched(currentState)
#do other stuff otherwise just don't do anything?!
except KeyboardInterrupt:
GPIO.cleanup()

11
sopel-bot/default.cfg Normal file
View File

@ -0,0 +1,11 @@
[core]
nick = ccchb-schalter
host = irc.hackint.org
use_ssl = true
verify_ssl = false
port = 6697
owner = ccchb-schalter
channels = #ccchb,#ccchb-dev
enable = spaceapi,admin
admins = genofire,paradx,pyropeter
auth_method = server

View File

@ -0,0 +1,63 @@
#!/usr/bin/env python3
import json
import sopel.module
SPACEAPI = "/var/www/html/spaceapi.json"
PLACE = "ccchb"
cache = {
"open": False
}
# opens the spaceapi json file, loads it and interpretes the json
def get_spaceapi():
with open(SPACEAPI, 'r') as infile:
data = json.load(infile)
return data
# generates a status message provides the current status
def status_msg(status):
status_text = "closed"
if status:
status_text = "open"
return '{} is {}'.format(PLACE, status_text)
# writes a message to the irc channel if the status has changed
def change_status(bot, status):
status_text = "closed"
if status:
status_text = "open"
for ch in bot.channels:
bot.notice('{} changed to {}'.format(PLACE, status_text), ch)
# reads the spaceapi file and checks if the status is up to date. Updates otherwise,
# this function is called every 5 seconds
def check_status(bot, human=False):
data = get_spaceapi()
status = data["state"]["open"]
if status != cache["open"]:
cache["open"] = status
change_status(bot, status)
status_text = status_msg(status)
for ch in bot.channels:
channel = bot.channels[ch]
topic_new = status_text
topic_cur = status_msg(not status)
if channel.topic != None:
topic_new = channel.topic.replace(topic_cur, topic_new)
topic_cur = channel.topic
if topic_new != topic_cur:
bot.write(('TOPIC', ch), topic_new)
if human:
bot.reply(status_text)
@sopel.module.interval(5)
def interval_check_status(bot):
check_status(bot)
@sopel.module.commands('status','help')
def cmd_check_status(bot, trigger):
check_status(bot, True)

30
spaceapi.json Normal file
View File

@ -0,0 +1,30 @@
{
"api": "0.13",
"space": "CCCHB",
"logo": "https://ccchb.de/logo/CCCHB-logo_256x256_bw.png",
"url": "https://ccchb.de/",
"location": {
"address": "Postamt 5, An der Weide 50a, 28195 Bremen, Germany",
"ext_floor": 1,
"lat": 53.0815,
"lon": 8.8154
},
"contact": {
"irc": "irc://irc.hackint.net/ccchb",
"ml": "ccc@lists.ccchb.de",
"issue_mail": "geno+ccc@fireorbit.de"
},
"issue_report_channels": [
"issue_mail",
"ml"
],
"state": {
"lastchange": 1518643002.5509002,
"open": false,
"icon": {
"open": "https://files.ccchb.de/assets/SpaceOpen.svg",
"closed": "https://files.ccchb.de/assets/SpaceClosed.svg"
}
},
"ext_ccc": "erfa"
}

12
systemd/ircbot.service Normal file
View File

@ -0,0 +1,12 @@
[Unit]
Description=Schalter IRC Bot
[Service]
ExecStart=/usr/bin/sopel
User=pi
Group=pi
Restart=always
RestartSec=300
[Install]
WantedBy=multi-user.target

13
systemd/schalter.service Normal file
View File

@ -0,0 +1,13 @@
[Unit]
Description=Eingangsschalter
[Service]
ExecStart=/home/pi/Eingangsschalter/schalter.py
WorkingDirectory=/home/pi/Eingangsschalter
User=pi
Group=pi
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target

92
www/index.html Normal file
View File

@ -0,0 +1,92 @@
<!DOCTYPE html>
<html>
<head>
<style>
body {
background-color: black;
color: white;
}
nav {
border-bottom: 2px solid green;
display: flex;
align-items:center;
flex-direction: row;
}
body.closed nav{
border-color: red;
}
#name {
font-size: 3em;
padding: auto;
}
#logo {
height: 4em;
margin-right: 10px;
}
#refresh {
margin-left: auto;
border: 5px solid green;
border-radius: 5px;
background: black;
color: white;
font-size: 2em;
}
body.closed #refresh {
border-color: red;
}
div#content {
display: flex;
justify-content: center;
}
#state {
margin: auto;
width: 40%;
}
</style>
</head>
<body>
<nav>
<img id="logo" src=""/>
<span id="name"></span>
<button id="refresh" type="button" onclick="load()">Update</button>
</nav>
<div id="content">
<img id="state" src=""/>
</div>
<script>
function load() {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "spaceapi.json", false);
xhttp.send();
var result = JSON.parse(xhttp.responseText);
document.title = result.space + " is " + (result.state.open ? 'open' : 'close');
document.getElementById("name").innerText = result.space;
document.getElementById("logo").src = result.logo;
var stateurl = result.state.open ? result.state.icon.open : result.state.icon.closed;
document.getElementById("state").src = stateurl;
var link = document.querySelector("link[rel*='icon']") || document.createElement('link');
link.type = 'image/x-icon';
link.rel = 'shortcut icon';
link.href = stateurl;
document.getElementsByTagName('head')[0].appendChild(link);
var body = document.querySelector("body");
if (!result.state.open) {
body.classList.add("closed");
}
else{
body.classList.remove("closed");
}
}
load();
window.setInterval(load, 60 * 1000);
</script>
</body>
</html>