#!/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 gammu import os import sys import time import yaml import smtplib import re import glob import shutil import random import string 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__))) # Set Default Encoding to UTF-8 reload(sys) # Reload does the trick! sys.setdefaultencoding('UTF8') # State Machine fuer Gammu sm = gammu.StateMachine() # Read Configuration from YAML-File with open("%s/bin/beielimon-config.yaml" % APP_ROOT, 'r') as stream: try: config_data = yaml.load(stream) except yaml.YAMLError as exc: print(exc) def send_sms(phonenumbers , text): for phonenumber in phonenumbers: message = { 'Text': text, 'SMSC': {'Location': 1}, 'Number': phonenumber } #GELD SPAREN sm.SendSMS(message) sm.SendSMS(message) print("Send SMS to %s, Text: %s" % (phonenumber, text)) def send_mail(send_from, send_to, subject, text, files=None): sm.Terminate() 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,"plain","utf-8")) for f in files or []: 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=120) 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)) # Wir reinitialisieren das Modem sm.Init() 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 , 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 ProcessSend_SMS_Queue(): files = glob.glob("%s/send_sms_queue/*yml" % (APP_ROOT)) for f in files: with open("%s" % f, 'r') as stream: try: sms_data = yaml.load(stream) except yaml.YAMLError as exc: print(exc) os.remove(f) send_sms(sms_data['phonenumbers'],sms_data['text']) def CreateAttachements(infotime): mypid = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(7)) 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))) files = glob.glob("%s/data/weight-*-%s.log" % (APP_ROOT,my_pattern)) 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) files = glob.glob("%s/data/swarmalarm-*-%s.log" % (APP_ROOT,my_pattern)) for s in config_data['scales']: filename = "%s/Schwarmalarm-%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\n" % (m.group(3),m.group(2),m.group(1),m.group(4))) else: file.write("Fehler beim Parsen: %s" % (line)) if with_data: res.append(filename) zipfile = "%s/%s" % (myzipdir,infotime) zipfile = "%s/%s" % (myzipdir,infotime) shutil.make_archive(zipfile, 'zip', mycsvdir) return [ "%s.zip" % (zipfile) ] def send_report(infotime): # Send EMail Report my_text = my_text = "Diese Meldung ist die Antwort auf die SMS-Anfrage \"info %s\"\n\n" % (infotime) my_text += "Letzte Messwerte:\n" for s in config_data['scales']: my_text += "%s: %s\n" % (s['alias'],GetLastValues(s['scale_uuid'])) my_text += "\n\nIm ZIP-File sind die Messwerte der angefragten Periode enthalten. Die Messdaten sind im CSV-Format abgespeichert und können z.B. mit Excel analysiert werden.\n\n" attachements = CreateAttachements(infotime) send_mail(config_data['mailfrom'],config_data['mailto'],'Messwerte BeieliPi',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 process_received_sms(phonenumber,message): # 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']: 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)) return 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) def main(): sm.ReadConfig() sm.Init() counter = 9999 while True: counter += 1 if counter > 1000: # Wir synchronisren die Zeit mit dem Internet sm.Terminate() os.system('/usr/bin/sudo %s/root-bin/sync_time_with_internet' % (APP_ROOT)) sm.Init() counter = 0 status = sm.GetSMSStatus() #print(status) remain = status['SIMUsed'] + status['PhoneUsed'] + status['TemplatesUsed'] if remain: firstsms = sm.GetNextSMS(Start = True, Folder = 0) #print("FIRSTSMS: %s" % (firstsms)) for x in range(len(firstsms)): sm.DeleteSMS(firstsms[x]['Folder'], firstsms[x]['Location']) #print("sm.DeleteSMS: %s %s" % (firstsms[x]['Folder'], firstsms[x]['Location'])) number = firstsms[x]['Number'] message = firstsms[x]['Text'] #print(number,message) print("process_received_sms %s %s" % (number,message)) process_received_sms(number,message) remain = remain - len(firstsms) sys.stdout.flush() ProcessSend_SMS_Queue() time.sleep(15) if __name__ == "__main__": main()