Skip to content
26 changes: 24 additions & 2 deletions baconbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,38 @@
import asyncio
import irc3
from irc3.plugins.command import command
from eval_arith import comp_expr, EvalConstant

logging.basicConfig(filename='bot.log',level=logging.DEBUG)
logger = logging.getLogger("BACONBOT")

from regner_det import get_weather

@irc3.plugin
class SwitchControllerPlugin:
jobs = [ ("raining", "#shelloutput", get_weather) ]

@irc3.plugin
class SwitchControllerPlugin(object):
"""
Plugin to control RF sockets.
"""
@command
def calc(self, mask, target, args):
""" Calc command

%%calc <expr>
"""
res = comp_expr.parseString(args["<expr>"])[0].eval()
self.bot.notice(target, str(res))

@command
def run_jobs(self, mask, target, args):
""" Run available jobs

%%run_jobs
"""
for job in jobs:
self.bot.notice(target, job)
self.bot.notice(target, job[2]())

def __init__(self, bot):
self.bot = bot
Expand Down
198 changes: 198 additions & 0 deletions eval_arith.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
# eval_arith.py
#
# Copyright 2009, Paul McGuire
#
# Expansion on the pyparsing example simpleArith.py, to include evaluation
# of the parsed tokens.
#
from pyparsing import Word, nums, alphas, Combine, oneOf, \
opAssoc, operatorPrecedence

class EvalConstant(object):
"Class to evaluate a parsed constant or variable"
vars_ = {}
def __init__(self, tokens):
self.value = tokens[0]
def eval(self):
if self.value in EvalConstant.vars_:
return EvalConstant.vars_[self.value]
else:
return float(self.value)

class EvalSignOp(object):
"Class to evaluate expressions with a leading + or - sign"
def __init__(self, tokens):
self.sign, self.value = tokens[0]
def eval(self):
mult = {'+':1, '-':-1}[self.sign]
return mult * self.value.eval()

def operatorOperands(tokenlist):
"generator to extract operators and operands in pairs"
it = iter(tokenlist)
while 1:
try:
yield (next(it), next(it))
except StopIteration:
break

class EvalMultOp(object):
"Class to evaluate multiplication and division expressions"
def __init__(self, tokens):
self.value = tokens[0]
def eval(self):
prod = self.value[0].eval()
for op,val in operatorOperands(self.value[1:]):
if op == '*':
prod *= val.eval()
if op == '/':
prod /= val.eval()
return prod

class EvalAddOp(object):
"Class to evaluate addition and subtraction expressions"
def __init__(self, tokens):
self.value = tokens[0]
def eval(self):
sum = self.value[0].eval()
for op,val in operatorOperands(self.value[1:]):
if op == '+':
sum += val.eval()
if op == '-':
sum -= val.eval()
return sum

class EvalComparisonOp(object):
"Class to evaluate comparison expressions"
opMap = {
"<" : lambda a,b : a < b,
"<=" : lambda a,b : a <= b,
">" : lambda a,b : a > b,
">=" : lambda a,b : a >= b,
"!=" : lambda a,b : a != b,
"=" : lambda a,b : a == b,
"LT" : lambda a,b : a < b,
"LE" : lambda a,b : a <= b,
"GT" : lambda a,b : a > b,
"GE" : lambda a,b : a >= b,
"NE" : lambda a,b : a != b,
"EQ" : lambda a,b : a == b,
"<>" : lambda a,b : a != b,
}
def __init__(self, tokens):
self.value = tokens[0]
def eval(self):
val1 = self.value[0].eval()
for op,val in operatorOperands(self.value[1:]):
fn = EvalComparisonOp.opMap[op]
val2 = val.eval()
if not fn(val1,val2):
break
val1 = val2
else:
return True
return False


# define the parser
integer = Word(nums)
real = Combine(Word(nums) + "." + Word(nums))
variable = Word(alphas,exact=1)
operand = real | integer | variable

signop = oneOf('+ -')
multop = oneOf('* /')
plusop = oneOf('+ -')

# use parse actions to attach EvalXXX constructors to sub-expressions
operand.setParseAction(EvalConstant)
arith_expr = operatorPrecedence(operand,
[
(signop, 1, opAssoc.RIGHT, EvalSignOp),
(multop, 2, opAssoc.LEFT, EvalMultOp),
(plusop, 2, opAssoc.LEFT, EvalAddOp),
])

comparisonop = oneOf("< <= > >= != = <> LT GT LE GE EQ NE")
comp_expr = operatorPrecedence(arith_expr,
[
(comparisonop, 2, opAssoc.LEFT, EvalComparisonOp),
])

def main():
# sample expressions posted on comp.lang.python, asking for advice
# in safely evaluating them
rules=[
'( A - B ) = 0',
'(A + B + C + D + E + F + G + H + I) = J',
'(A + B + C + D + E + F + G + H) = I',
'(A + B + C + D + E + F) = G',
'(A + B + C + D + E) = (F + G + H + I + J)',
'(A + B + C + D + E) = (F + G + H + I)',
'(A + B + C + D + E) = F',
'(A + B + C + D) = (E + F + G + H)',
'(A + B + C) = (D + E + F)',
'(A + B) = (C + D + E + F)',
'(A + B) = (C + D)',
'(A + B) = (C - D + E - F - G + H + I + J)',
'(A + B) = C',
'(A + B) = 0',
'(A+B+C+D+E) = (F+G+H+I+J)',
'(A+B+C+D) = (E+F+G+H)',
'(A+B+C+D)=(E+F+G+H)',
'(A+B+C)=(D+E+F)',
'(A+B)=(C+D)',
'(A+B)=C',
'(A-B)=C',
'(A/(B+C))',
'(B/(C+D))',
'(G + H) = I',
'-0.99 LE ((A+B+C)-(D+E+F+G)) LE 0.99',
'-0.99 LE (A-(B+C)) LE 0.99',
'-1000.00 LE A LE 0.00',
'-5000.00 LE A LE 0.00',
'A < B',
'A < 7000',
'A = -(B)',
'A = C',
'A = 0',
'A GT 0',
'A GT 0.00',
'A GT 7.00',
'A LE B',
'A LT -1000.00',
'A LT -5000',
'A LT 0',
'A=(B+C+D)',
'A=B',
'I = (G + H)',
'0.00 LE A LE 4.00',
'4.00 LT A LE 7.00',
'0.00 LE A LE 4.00 LE E > D',
]
vars_={'A': 0, 'B': 1.1, 'C': 2.2, 'D': 3.3, 'E': 4.4, 'F': 5.5, 'G':
6.6, 'H':7.7, 'I':8.8, 'J':9.9}

# define tests from given rules
tests = []
for t in rules:
t_orig = t
t = t.replace("=","==")
t = t.replace("EQ","==")
t = t.replace("LE","<=")
t = t.replace("GT",">")
t = t.replace("LT","<")
t = t.replace("GE",">=")
t = t.replace("LE","<=")
t = t.replace("NE","!=")
t = t.replace("<>","!=")
tests.append( (t_orig,eval(t,vars_)) )

# copy vars_ to EvalConstant lookup dict
EvalConstant.vars_ = vars_
for test,expected in tests:
ret = comp_expr.parseString(test)[0]
print(test, expected, ret.eval())

if __name__=='__main__':
main()
54 changes: 54 additions & 0 deletions regner_det.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import colorsys
import requests
import sys
from PIL import Image
from io import BytesIO
import itertools

def chunks(iterable,size):
""" http://stackoverflow.com/a/434314/309483 """
it = iter(iterable)
chunk = tuple(itertools.islice(it,size))
while chunk:
yield chunk
chunk = tuple(itertools.islice(it,size))

def getimg():
data = requests.get("http://www.wetteronline.de/?ireq=true&pid=p_radar_forecast&src=radar/vermarktung/p_radar_map_forecast/forecastLoop/DL/latestForecastLoop.gif", stream=True)
return Image.open(BytesIO(data.raw.data))

def get_pixels_in_all_frames(im):
try:
while 1:
im.seek(im.tell()+1)
# do something to im
for x in range(520):
for y in range(571):
yield im.load()[x,y]
except EOFError:
pass # end of sequence

def countblue(im):
for idx, i in enumerate(chunks(get_pixels_in_all_frames(im), 4)):
hsv = colorsys.rgb_to_hsv(r=i[0], g=i[1], b=i[2])
assert i[3] == 0
if 120 <= hsv[0] <= 360:
yield 1

def get_weather():
im = getimg()
number_of_frames = 1
try:
while 1:
im.seek(im.tell()+1)
number_of_frames += 1
except EOFError:
pass # end of sequence
fraction = sum(countblue(im)) / 520*571*number_of_frames
if fraction > 0.5:
return fraction
else:
return None

if __name__=="__main__":
print(get_weather())