Beta Release

This commit is contained in:
2017-11-09 13:46:58 +01:00
parent b379570033
commit e3e1387117
62 changed files with 32013 additions and 26 deletions
+25 -6
View File
@@ -1,7 +1,26 @@
scale_interfaces:
- usb_pce
read_scale_interval_sec: 5
beielipi_mobile_number: "077 461 19 91"
scales:
- alias: "Waage Volk 1"
scale_uuid: "46335715-8454-483b-a17b-571619c5015d"
interface_type: usb_pce
interface_name: ttyUSB0
sms_alert_phonenumbers:
- "+41765006123"
- alias: "Waage Volk 2"
scale_uuid: "46335715-8454-483b-a17b-571619c5015e"
interface_type: dummy
sms_alert_phonenumbers:
- "+41765006124"
read_scale_interval_sec: 300
number_of_samples: 5
sms_alert_phonenumbers:
- "0765006123"
swarm_alarm_threshold_gram: 50
swarm_alarm_threshold_gram: 500
mailserver: mail.nbit.ch
mailserver_port: 587
mailfrom: info@nbit.ch
mailto: joerg.lehmann@nbit.ch
mailuser: nbitinf@nbit.ch
mailpwd: ukihefak27
balance_number: "444"
balance_command: "STATUS"
forward_sms_from_this_number: "444"
master_sms_number: "+41765006123"
+111 -20
View File
@@ -11,15 +11,21 @@
from __future__ import print_function
import gammu.smsd
import os
import sys
import serial
import time
import yaml
import random
# Root Path
APP_ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
# Read Configuration from YAML-File
with open("beielimon-config.yaml", 'r') as stream:
with open("%s/bin/beielimon-config.yaml" % (APP_ROOT), 'r') as stream:
try:
config_data = yaml.load(stream)
#print(config_data)
except yaml.YAMLError as exc:
print(exc)
@@ -30,22 +36,43 @@ INVALID_VALUE = -999
smsd = gammu.smsd.SMSD('/etc/gammu-smsdrc')
class Scale(object):
def __init__(self):
def __init__(self, scale_config):
self.last_values = []
self.scale_config = scale_config
def __del__(self):
pass
def LogValue(self,weigh_in_gram,swarm_alarm):
cur_time = time.localtime()
timestamp = time.strftime("%Y-%m-%d %H:%M", cur_time)
year = time.strftime("%Y", cur_time)
month = time.strftime("%m", cur_time)
day = time.strftime("%d", cur_time)
if swarm_alarm:
prefix = 'swarmalarm'
else:
prefix = 'weight'
datafilename = "%s/data/%s-%s-%s%s%s.log" % (APP_ROOT,prefix,self.scale_config['scale_uuid'],year,month,day)
#print('Log to File %s' % (datafilename))
with open(datafilename, 'a') as file:
file.write('%s,%d\n' % (timestamp,weigh_in_gram))
def AppendReading(self,weigh_in_gram):
self.last_values.append(weigh_in_gram)
if len(self.last_values) > config_data['number_of_samples']:
self.last_values = self.last_values[1:]
print('DEBUG WEIGHT: %d' % (weigh_in_gram))
print(self.last_values)
#print('DEBUG WEIGHT: %d' % (weigh_in_gram))
#print(self.last_values)
# Wir loggen den Wert noch
self.LogValue(weigh_in_gram,False)
def Read(self):
pass
def CalibrateToZero(self):
pass
def SwarmAlarm(self):
return (self.GetWeighLoss() > config_data['swarm_alarm_threshold_gram'])
@@ -58,13 +85,16 @@ class Scale(object):
def GetWeighLoss(self):
last_value = self.GetLastValue()
max_value = max(self.last_values or [0])
print('BBB: ',max_value,last_value)
#print('BBB: ',max_value,last_value)
return (max_value - last_value)
def GetScaleConfig(self):
return self.scale_config
class ScaleUSB_PCE(Scale):
def __init__(self,serial_int):
Scale.__init__(self)
def __init__(self,serial_int, scale_config):
Scale.__init__(self, scale_config)
self.ser = serial_int
def Read(self):
@@ -84,12 +114,57 @@ class ScaleUSB_PCE(Scale):
if res != INVALID_VALUE:
self.AppendReading(res)
class ScaleBT_KDPSB(Scale):
def __init__(self,serial_int, scale_config):
Scale.__init__(self, scale_config)
self.ser = serial_int
def Read(self):
res = INVALID_VALUE
try:
self.ser.write('\x02G\x03')
except:
print('DEBUG FEHLER BEIM SCHREIBEN')
time.sleep(1)
try:
weight_string = self.ser.read(12)
except:
print('DEBUG FEHLER BEIM LESEN')
weight_string=''
#print('DEBUG READ STRING HEX: %s' % (':'.join(x.encode('hex') for x in weight_string)))
#print('DEBUG READ STRING: %s' % (weight_string))
if len(weight_string) == 12:
#print('DEBUG READ STRING BBB: %s' % (weight_string[1:8]))
res = int(float(weight_string[1:8])*1000)
#print('DEBUG GEWICHT IN GRAM: %s' % (weight_string))
if res != INVALID_VALUE:
self.AppendReading(res)
def CalibrateToZero(self):
try:
self.ser.write('\x02T\x03')
except:
print('DEBUG FEHLER BEIM KALIBRIEREN')
time.sleep(1)
class ScaleDummy(Scale):
def __init__(self,serial_int):
pass
def __init__(self,scale_config):
Scale.__init__(self, scale_config)
def Read(self):
pass
# Gewichts- Zu/Abnahme ist Random, manchmal gibt es einen
# Zufaelligen Schwarmalarm
delta = random.randint(-2, 4)
if (random.randint(0,1000) == 500):
delta = random.randint(-1000, - 501)
last_value = self.GetLastValue()
# Wir duerfen nicht negativ werden...
if (last_value + delta < 0):
delta = random.randint(0,4)
self.AppendReading(last_value + delta)
def send_sms(phonenumbers , text):
@@ -100,18 +175,33 @@ def send_sms(phonenumbers , text):
'Number': phonenumber
}
smsd.InjectSMS([message])
#GELD SPAREN smsd.InjectSMS([message])
#print("Send SMS to %s, Text: %s" % (phonenumber, text))
def main():
scales = []
for scale_interface in config_data['scale_interfaces']:
if scale_interface == 'usb_pce':
ser = serial.Serial(port='/dev/ttyUSB0',
for scale_config in config_data['scales']:
if scale_config['interface_type'] == 'bt_kdpsb':
#print('DEBUG: sudo /usr/bin/rfcomm bind ' + scale_config['interface_name'] + ' ' + scale_config['address'] + ' ' + scale_config['interface_channel'])
os.system('sudo /usr/bin/rfcomm bind ' + scale_config['interface_name'] + ' ' + scale_config['address'] + ' ' + scale_config['interface_channel'])
ser = serial.Serial(port='/dev/' + scale_config['interface_name'],
baudrate=9600,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_EVEN,
timeout=20000)
scale=ScaleUSB_PCE(ser)
timeout=20)
scale=ScaleBT_KDPSB(ser, scale_config)
#scale.CalibrateToZero()
scales.append(scale)
elif scale_config['interface_type'] == 'usb_pce':
ser = serial.Serial(port='/dev/' + scale_config['interface_name'],
baudrate=9600,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_EVEN,
timeout=20)
scale=ScaleUSB_PCE(ser, scale_config)
scales.append(scale)
elif scale_config['interface_type'] == 'dummy':
scale=ScaleDummy(scale_config)
scales.append(scale)
# Main Loop
@@ -119,12 +209,13 @@ def main():
for scale in scales:
scale.Read()
if scale.SwarmAlarm():
date_time = time.strftime("%d.%m.%Y %H:%M:%S")
date_time = time.strftime("%d.%m.%Y %H:%M")
last_value = scale.GetLastValue()
weigh_loss = scale.GetWeighLoss()
sms_message = '*** Schwarmalarm ***\nDatum/Zeit: \nLetztes Gewicht [g]: %d\nGewichtsverlust [g]: %d' % (date_time,last_value,weigh_loss)
print(config_data['sms_alert_phonenumbers'],sms_message)
send_sms(config_data['sms_alert_phonenumbers'],sms_message)
# Wir loggen den Wert noch
scale.LogValue(last_value,True)
sms_message = '*** Schwarmalarm ***\nDatum/Zeit: %s\nWaage: %s\nLetztes Gewicht [g]: %d\nGewichtsverlust [g]: %d' % (date_time,scale.GetScaleConfig()['alias'],last_value,weigh_loss)
send_sms(scale.GetScaleConfig()['sms_alert_phonenumbers'],sms_message)
scale.ResetValues()
time.sleep(config_data['read_scale_interval_sec'])
+284
View File
@@ -0,0 +1,284 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# vim: expandtab sw=4 ts=4 sts=4:
#
# Beehive-Monitoring, process SMS Requests
#
# Author: Joerg Lehmann, nbit Informatik GmbH
#
"""Beehive Monitoring - SMS Processing"""
from __future__ import print_function
import os
import sys
import time
import yaml
import smtplib
import re
import glob
import shutil
from os.path import basename
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
# Root Path
APP_ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
# Read Configuration from YAML-File
with open("%s/bin/beielimon-config.yaml" % APP_ROOT, 'r') as stream:
try:
config_data = yaml.load(stream)
#print(config_data)
except yaml.YAMLError as exc:
print(exc)
def send_sms(phonenumbers , text):
print("BBB: %s" % (text))
for phonenumber in phonenumbers:
message = {
'Text': text,
'SMSC': {'Location': 1},
'Number': phonenumber
}
#os.system('echo "%s" | /usr/bin/gammu-smsd-inject TEXT %s' % (text,phonenumber))
print("YYY Send SMS to %s, Text: %s" % (phonenumber, text))
def send_mail(send_from, send_to, subject, text, files=None):
os.system('/usr/bin/sudo %s/root-bin/connect_to_internet' % (APP_ROOT))
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = send_to
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach(MIMEText(text))
print("XXX: %s" % (files))
for f in files or []:
print("AAA: %s" % (f))
with open(f, "rb") as fil:
part = MIMEApplication(
fil.read(),
Name=basename(f)
)
# After the file is closed
part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
msg.attach(part)
smtp = smtplib.SMTP(config_data['mailserver'],config_data['mailserver_port'],timeout=30)
#smtp.set_debuglevel(1)
smtp.ehlo()
smtp.starttls()
smtp.login(config_data['mailuser'], config_data['mailpwd'])
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
os.system('/usr/bin/sudo %s/root-bin/disconnect_from_internet' % (APP_ROOT))
def send_help(phonenumber,command):
# SMS Maximale Groesse: 140 Zeichen
if command == '':
sms_message = """Moegliche Befehle:
help, info, balance, reboot, shutdown, hotspot
Naehere Hilfe: help <befehl>, z.B. help info"""
elif command == 'info':
sms_message = """info - letzte Messwerte (SMS)
info 2017 - Messwerte 2017 (EMail)
info 201711 - Messwerte Nov. 2017
info 20171102 - Messwerte 2. Nov. 2017"""
elif command == 'help':
sms_message = "Zeigt die moeglichen Befehle an"
elif command == 'balance':
sms_message = "Anforderung Info zum Prepaid-Guthaben"
elif command == 'reboot':
sms_message = "Neustart des Raspberry Pi's"
elif command == 'shutdown':
sms_message = """Herunterfahren des Raspberry Pi's
ACHTUNG: ZUM STARTEN MUSS STROM AUS- UND WIEDER EINGESTECKT WERDEN!
"""
elif command == 'hotspot':
sms_message = """hotspot on - Hotspot Funktion einschalten
hotspot off - Hotspot ausschalten
Hotspot erlaubt ein Auslesen per Smartphone/Table (WLAN)"""
send_sms([phonenumber],sms_message)
def GetLastValues(scale_uuid):
files = glob.glob("%s/data/weight-%s-????????.log" % (APP_ROOT,scale_uuid))
if len(files) > 0:
with open(sorted(files)[-1], "r") as f:
for line in f: pass
result = line
# Beispiel: 2017-11-07 08:23,0
m = re.match("(\d{4})-(\d{2})-(\d{2}) (\d\d:\d\d),(\d+)", result)
if m:
return "%sg (%s.%s.%s %s)" % (m.group(5),m.group(3),m.group(2),m.group(1),m.group(4))
else:
return "Fehler beim Parsen: %s" % (result)
else:
return "keine Messwerte"
def CreateAttachements(infotime):
mypid = os.getpid()
mycsvdir = "%s/tmp/%s/csv" % (APP_ROOT,mypid)
if not os.path.exists(mycsvdir):
os.makedirs(mycsvdir)
myzipdir = "%s/tmp/%s/zip" % (APP_ROOT,mypid)
if not os.path.exists(myzipdir):
os.makedirs(myzipdir)
res = []
my_pattern = '%s%s' % (infotime,'?' * (8 - len(infotime)))
print('AAA: %s' % (my_pattern))
files = glob.glob("%s/data/weight-*-%s.log" % (APP_ROOT,my_pattern))
for f in files:
print("%s" % (f))
for s in config_data['scales']:
filename = "%s/%s-%s.csv" % (mycsvdir,s['alias'].replace(' ','_'),infotime)
with_data = False
with open(filename, 'a') as file:
for ifile in sorted(files):
if (s['scale_uuid'] in ifile) and (infotime in ifile):
with_data = True
with open(ifile, 'r') as ifile:
for line in ifile:
m = re.match("(\d{4})-(\d{2})-(\d{2}) (\d\d:\d\d,(\d+)", line)
if m:
file.write("%s.%s.%s %s,%s\n" % (m.group(3),m.group(2),m.group(1),m.group(4),m.group(5)))
else:
file.write("Fehler beim Parsen: %s" % (line))
if with_data:
res.append(filename)
zipfile = "%s/%s" % (myzipdir,infotime)
shutil.make_archive(zipfile, 'zip', mycsvdir)
#print("ATTA: %s" % (res))
return [ "%s.zip" % (zipfile) ]
def send_report(infotime):
# Send EMail Report
my_text = "Letzte Messwerte:\n"
for s in config_data['scales']:
my_text += "%s: %s\n" % (s['alias'],GetLastValues(s['scale_uuid']))
attachements = CreateAttachements(infotime)
#send_mail(config_data['mailfrom'],config_data['mailto'],'Messwerte mini-beieli',my_text,attachements)
def send_info_sms(phonenumber):
my_text = "Letzte Messwerte:\n"
for s in config_data['scales']:
my_text += "%s: %s\n" % (s['alias'],GetLastValues(s['scale_uuid']))
send_sms([phonenumber],my_text)
def send_info(phonenumber, message_uc):
m = re.match(".*(INFO)\s+(\d{8})", message_uc)
if m:
send_report(m.group(2))
else:
m = re.match(".*(INFO)\s+(\d{6})", message_uc)
if m:
send_report(m.group(2))
else:
m = re.match(".*(INFO)\s+(\d{4})", message_uc)
if m:
send_report(m.group(2))
else:
send_info_sms(phonenumber)
def balance():
send_sms([config_data['balance_number']],config_data['balance_command'])
def reboot():
os.system('/usr/bin/sudo /sbin/init 6')
def shutdown():
os.system('/usr/bin/sudo /sbin/init 0')
def hotspot_on():
os.system('/usr/bin/sudo %s/root-bin/hotspot on' % (APP_ROOT))
def hotspot_off():
os.system('/usr/bin/sudo %s/root-bin/hotspot off' % (APP_ROOT))
def command_not_understood(phonenumber, message):
send_sms([phonenumber],'Befehl nicht verstanden: %s\n\nMoegliche Befehle: help, info, balance, reboot, shutdown, hotspot' % (message[:50]))
def main():
print(config_data)
print('Number of arguments:', len(sys.argv), 'arguments.')
print('Argument List:', str(sys.argv))
if len(sys.argv) != 3:
print("Da kann etwas nicht stimmen, ungueltige Anzahl Argumente")
sys.exit(1)
phonenumber = sys.argv[1]
message = sys.argv[2]
# Falls es von forward_sms_from_this_number kommt, machen wir ein Foward an
# die Master Nummer
if phonenumber == config_data['forward_sms_from_this_number']:
print("AAA: %s" % (message))
#send_mail(config_data['mailfrom'],config_data['mailto'],'Beielimon Subject',message,[])
send_sms([config_data['master_sms_number']],message)
else:
# message in Grossbuchstaben (damit Gross-/Kleinschreibung keine Rolle spielt)
message_uc = message.upper()
# Bestimmung, ob es eine gueltige Telefonnummer ist
valid_number = False
for s in config_data['scales']:
if phonenumber in s['sms_alert_phonenumbers']:
valid_number = True
if not valid_number:
print("Da versucht ein unberechtigter, etwas abzufragen... (Nummer: %s)" % (phonenumber))
sys.exit(2)
if 'HELP INFO' in message_uc:
send_help(phonenumber,'info')
elif 'HELP HELP' in message_uc:
send_help(phonenumber,'help')
elif 'HELP BALANCE' in message_uc:
send_help(phonenumber,'balance')
elif 'HELP REBOOT' in message_uc:
send_help(phonenumber,'reboot')
elif 'HELP SHUTDOWN' in message_uc:
send_help(phonenumber,'shutdown')
elif 'HELP HOTSPOT' in message_uc:
send_help(phonenumber,'hotspot')
elif 'HELP' in message_uc:
send_help(phonenumber,'')
elif 'INFO' in message_uc:
send_info(phonenumber, message_uc)
elif 'BALANCE' in message_uc:
balance()
elif 'REBOOT' in message_uc:
reboot()
elif 'SHUTDOWN' in message_uc:
shutdown()
elif 'HOTSPOT OFF' in message_uc:
hotspot_off()
elif 'HOTSPOT ON' in message_uc:
hotspot_on()
else:
command_not_understood(phonenumber, message)
if __name__ == "__main__":
main()