186 lines
6.1 KiB
Python
Executable File
186 lines
6.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# ==========================================================================
|
|
#
|
|
# ZoneMinder Alarm Server Script for Netsurveillence Software cameras, $Date$, $Revision$
|
|
# Copyright (C) 2022
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
#
|
|
# ==========================================================================
|
|
|
|
|
|
|
|
# Adds pyzm support
|
|
import pyzm.api as zmapi
|
|
import pyzm.ZMLog as zmlog
|
|
import pyzm.helpers.utils as utils
|
|
|
|
import os, sys, struct, json
|
|
from time import sleep
|
|
#import time
|
|
from socket import *
|
|
# from datetime import *
|
|
# telnet
|
|
from telnetlib import Telnet
|
|
# multi threading
|
|
from threading import Thread
|
|
|
|
def writezmlog(m,s):
|
|
zmlog.init()
|
|
zmlog.Info(m+s)
|
|
# zmlog.close()
|
|
|
|
def alarm_thread(m, monid,eventlenght):
|
|
import subprocess
|
|
print("Monitor " + str(monid)+" entered alarm_thread...")
|
|
result = subprocess.run(['zmu','-m', str(monid), '-s'] ,stdout=subprocess.PIPE)
|
|
if result.stdout.decode('utf-8') != '3\n':
|
|
print('Changing monitor '+ str(monid) + ' status to Alarm...')
|
|
m.arm()
|
|
sleep(eventlenght)
|
|
m.disarm()
|
|
else:
|
|
print('Monitor '+ str(monid) + ' already in status Alarm...')
|
|
print('Finishing thread...')
|
|
|
|
|
|
def event_thread(m_id,eventlenght):
|
|
import subprocess
|
|
print("Monitor " + str(m_id)+" entered event_thread...")
|
|
result = subprocess.run(['zmu','-m', str(m_id), '-x'] ,stdout=subprocess.PIPE)
|
|
if result.stdout.decode('utf-8') == '0\n':
|
|
print('Firing monitor '+ str(m_id) + ' trigger...')
|
|
telbuff = str(m_id) + '|on+'+str(eventlenght)+'|1|Human Motion Detected|'
|
|
with Telnet('localhost', 6802) as tn:
|
|
tn.write(telbuff.encode('ascii') + alarm_desc.encode('ascii') + b'\n')
|
|
tn.read_until(b'off')
|
|
else:
|
|
print('Monitor '+ str(m_id) + ' already triggered, doing nothing...')
|
|
print('Finishing thread...')
|
|
|
|
|
|
|
|
def tolog(s):
|
|
logfile = open(datetime.now().strftime('%Y_%m_%d_') + log, 'a+')
|
|
logfile.write(s)
|
|
logfile.close()
|
|
|
|
|
|
def GetIP(s):
|
|
return inet_ntoa(struct.pack('<I', int(s, 16)))
|
|
|
|
|
|
# config variables
|
|
eventlenght = 60
|
|
wrzmlog = 'n'
|
|
wrzmevent ='n'
|
|
rsealm = 'n'
|
|
port = '15002'
|
|
|
|
if len(sys.argv) > 1:
|
|
keys = ["--log=","-l=","--alarm=","-a=","--port=","-p=","--event=","-e="]
|
|
for i in range(1,len(sys.argv)):
|
|
for key in keys:
|
|
if sys.argv[i].find(key) == 0:
|
|
if key == "--log=" or key == "-l=":
|
|
wrzmlog=sys.argv[i][len(key):]
|
|
elif key == "--alarm=" or key == "-a=":
|
|
rsealm=sys.argv[i][len(key):]
|
|
elif key == "--port=" or key == "-p=":
|
|
port=sys.argv[i][len(key):]
|
|
elif key == "--event=" or key == "-e=":
|
|
wrzmevent=sys.argv[i][len(key):]
|
|
break
|
|
|
|
else:
|
|
print('Usage: %s [--port|-p=<value> --log|-l=<y/n> --alarm|-a=<y/n> --event|-e=<y/n>]' % os.path.basename(sys.argv[0]))
|
|
sys.exit(1)
|
|
|
|
print ('Create log entry: ', wrzmlog)
|
|
print ('Trigger event: ', wrzmlog)
|
|
print ('Raise Alarm: ', rsealm)
|
|
|
|
server = socket(AF_INET, SOCK_STREAM)
|
|
server.bind(('0.0.0.0', int(port)))
|
|
# server.settimeout(0.5)
|
|
server.listen(1)
|
|
|
|
log = "AlarmServer.log"
|
|
|
|
conf = utils.read_config('/etc/zm/secrets.ini')
|
|
api_options = {
|
|
'apiurl': utils.get(key='ZM_API_PORTAL', section='secrets', conf=conf),
|
|
'portalurl':utils.get(key='ZM_PORTAL', section='secrets', conf=conf),
|
|
'user': utils.get(key='ZM_USER', section='secrets', conf=conf),
|
|
#'disable_ssl_cert_check': True
|
|
}
|
|
|
|
zmapi = zmapi.ZMApi(options=api_options)
|
|
|
|
# importing the regex to get ip out of path
|
|
import re
|
|
#define regex pattern for IP addresses
|
|
pattern =re.compile('''((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)''')
|
|
# store the response of URL
|
|
#process monitors create dict of monitors
|
|
list_monit = {}
|
|
zm_monitors = zmapi.monitors()
|
|
for m in zm_monitors.list():
|
|
ip_v4=pattern.search(m.get()['Path'])
|
|
list_monit[ip_v4.group()]=m.id()
|
|
|
|
writezmlog('Listening on port: '+port,' AlarmServer.py')
|
|
print ('Listening on port: '+port)
|
|
#run Alarm Server
|
|
while True:
|
|
try:
|
|
conn, addr = server.accept()
|
|
head, version, session, sequence_number, msgid, len_data = struct.unpack(
|
|
'BB2xII2xHI', conn.recv(20)
|
|
)
|
|
sleep(0.1) # Just for receive whole packet
|
|
data = conn.recv(len_data)
|
|
conn.close()
|
|
# make the json a Dictionary
|
|
reply = json.loads(data)
|
|
# get ip
|
|
ip_v4 = GetIP(reply.get('Address'))
|
|
# get alarm_event_desc
|
|
alarm_desc = reply.get('Event')
|
|
# print(datetime.now().strftime('[%Y-%m-%d %H:%M:%S]>>>'))
|
|
print ('Ip Address: ',ip_v4)
|
|
print ("Alarm Description: ", alarm_desc)
|
|
print('<<<')
|
|
# tolog(repr(data) + "\r\n")
|
|
if alarm_desc == 'HumanDetect':
|
|
if wrzmlog == 'y':
|
|
writezmlog(alarm_desc+' in monitor ',str(list_monit[ip_v4]))
|
|
if rsealm == 'y':
|
|
print ("Triggering Alarm...")
|
|
mthread = Thread(target=alarm_thread, args=(zm_monitors.find(list_monit[ip_v4]),list_monit[ip_v4],eventlenght))
|
|
mthread.start()
|
|
elif wrzmevent == 'y':
|
|
print ("Triggering Event Rec on zmtrigger...")
|
|
mthread = Thread(target=event_thread, args=(list_monit[ip_v4],eventlenght))
|
|
mthread.start()
|
|
except (KeyboardInterrupt, SystemExit):
|
|
break
|
|
server.close()
|
|
# needs to be closed again... otherwise it will crash on exit.
|
|
zmlog.close()
|
|
sys.exit(1)
|