Disclaimer
This article contains a number of software code written in Python. Due to the fact that the author of an article by profession is a sysadmin, but not a programmer, the style and quality of this code can cause the manifestation of uncontrollable emotions among professionals. Please stop reading immediately if the appearance of an inaccurate or sub-optimal code may adversely affect your mental state.
Formulation of the problem
The main reason for the project, was a cold with the consequent: an excess of free time and the inability to leave the house. Rummaging in my desk, I found:
Of all the above, it was decided to build a home video surveillance system with intrusion alert functionality. A telegram bot was chosen as the platform. The bot has the following advantages over other possible implementations (web, mobile application):
Using a cursory analysis of online publications, no existing solutions were found.
Step 1. operating system
Raspbian was used as the operating system. For those who do not know, this is a Debian build optimized for work on the RaspberryPi hardware. The system is characterized by stability, a large number of available application software, and good documentation. System installation is trivial and repeatedly described in different sources. I will not dwell on this in detail, I will only say that it all comes down to downloading a disk image and recording it on an SD card. (Obviously, the version without GUI (lite) was used ) Regarding the default settings, the following changes were made:
apt-get install python3-pip supervisor
pip3 install PyTelegramBotAPI
Step2. Image capture
Initially, I planned to use some kind of ready-made solution for saving images from a webcam, and then independently engage in motion detection, but to my luck, Motion was discovered - a finished product that does exactly what I need: captures images from a webcam and determines are there any changes on them The package is included in the standard repository and its installation does not cause difficulties:
apt-get install motion
The configuration file (/etc/motion/motion.conf) is so extensive that within the framework of this article it is impossible to describe it completely, I’ll dwell only on those parameters that are significant or have been changed from the standard ones:
# - videodevice /dev/video0 # ( . ) width 1280 height 720 # ( 2, 100) # CPU "" framerate 4 # event_gap 0 # jpg 75 output_pictures on quality 75 picture_type jpeg # ffmpeg_output_movies off # 30 () " " snapshot_interval 30 # locate_motion_mode on locate_motion_style box # target_dir /var/lib/motion # ( snapshot) snapshot_filename %v-%Y%m%d%H%M%S-snapshot # ! . # : # 1970 + # # , ... picture_filename %s%q
Motion automatically creates a symlink to the last saved snapshot named lastsnap.jpg
Step 3. Programming
Suddenly I had to write significantly less than I had originally planned. The program consists of two small scripts and a configuration file. Additionally, in two text files I store information about the mode of operation (the mode of intrusion detection is on or off) and the last processed image.
The following information is stored in the config.py configuration file: telegram-api-token (how to get it, it is written in detail here ), a list of user IDs for which access is allowed, the name of the file with the last snapshot, the path to the folder with all the snapshots.
token = '4345435465:AsdfzzsdxgsYnb8DxDtn2L5KjfePsXozjv-o0' users=['1234567890','0987654321'] lastimage='/var/lib/motion/lastsnap.jpg' motiondir='/var/lib/motion'
Actually the bot itself. It has the following features:
import config import telebot from telebot import types import logging import datetime logger = telebot.logger telebot.logger.setLevel(logging.INFO) # Outputs debug messages to console. bot = telebot.TeleBot(config.token, threaded=True) ### def autor(chatid): strid = str(chatid) for item in config.users: if item == strid: return True return False ### def sendall(text): if len(config.users) > 0: for user in config.users: try: bot.send_message(user, text) except: print(str(datetime.datetime.now()) + ' ' + ' ' + text + ' ' + str( user)) ### def checkmode(): try: mode_file = open("mode.txt", "r") modestring = mode_file.read() mode_file.close() if modestring == '1': return True else: return False except: return False print(str(datetime.datetime.now()) + ' ' + ' , !') sendall(str(datetime.datetime.now()) + ' ' + ' , !') ### @bot.message_handler(commands=['', 'start', '']) def menu(message): if autor(message.chat.id): markup = types.ReplyKeyboardMarkup() markup.row('/', '/') if checkmode(): bot.send_message(message.chat.id, ' .', reply_markup=markup) else: bot.send_message(message.chat.id, ' .', reply_markup=markup) try: f = open(config.lastimage, 'rb') bot.send_photo(message.chat.id, f) except: bot.send_message(message.chat.id, ' ') else: markup = types.ReplyKeyboardMarkup() markup.row('/') bot.send_message(message.chat.id, ' . ID: ' + str(message.chat.id), reply_markup=markup) ### @bot.message_handler(commands=['']) def toggle(message): if autor(message.chat.id): try: if checkmode(): last_file = open("mode.txt", "w") last_file.write('0') last_file.close() sendall(' ' + message.chat.first_name + ' ') else: last_file = open("mode.txt", "w") last_file.write('1') last_file.close() sendall(' ' + message.chat.first_name + ' ') except: bot.send_message(message.chat.id, ' ') print(str(datetime.datetime.now()) + ' ' + " ") menu(message) if __name__ == '__main__': bot.polling(none_stop=False)
The second script, run at regular intervals, checks if there are raw jpg files without the word snapshot in the name, and if enabled, the detection mode sends these files to all bot users.
import datetime import logging import os import time import telebot import config logger = telebot.logger telebot.logger.setLevel(logging.INFO) # Outputs debug messages to console. bot = telebot.TeleBot(config.token, threaded=True) files = [] clearfiles = [] tosend = [] tosendfull = [] ### def checkmode(): try: mode_file = open("mode.txt", "r") modestring = mode_file.read() mode_file.close() if modestring == '1': return True else: return False except: return False ## def sendall(filename): for username in config.users: try: f = open(filename, 'rb') bot.send_photo(username, f) except: print( str(datetime.datetime.now()) + ' ' + ' ' + filename + ' ' + username) ## def writeproc(filename): try: last_file = open("last.txt", "w") last_file.write(filename) last_file.close() return last_file.close() except: return False ## def readproc(): try: last_file = open("last.txt", "r") lasstring = last_file.read() last_file.close() lastint = str(lasstring) return lastint except: return -1 ## processed = readproc() if processed == -1: print(str(datetime.datetime.now()) + ' ' + ' . ') quit(2) ## files = os.listdir(config.motiondir) files = filter(lambda x: x.endswith('.jpg'), files) ## , for file in files: if ('snapshot' in file) or ('last' in file) or ('-' in file): pass else: clearfile = file[:-4] clearfiles.append(clearfile) clearfiles.sort() ## for file in clearfiles: if int(file) > int(processed): tosend.append(file) ### : if len(tosend) > 0: try: if writeproc(tosend[-1]) == False: print(str(datetime.datetime.now()) + ' ' + ' . !') quit(2) else: print(str(datetime.datetime.now()) + ' ' + ' ') ### - ## if checkmode(): ## for filename in tosend: fullname = config.motiondir + '/' + filename + '.jpg' tosendfull.append(fullname) ## for filename in tosendfull: sendall(filename) time.sleep(1) else: print(str(datetime.datetime.now()) + ' ' + ' ') except: print(str(datetime.datetime.now()) + ' ' + ' ') else: print(str(datetime.datetime.now()) + ' ' + ' ')
Step 4. Putting it all together
I placed all the scripts in the / home / bigbro / bot directory. For start, control and logging used supervisor. Accordingly, in the /etc/supervisor/conf.d directory, I created files of approximately the following form:
[program:bot] directory=/home/bigbro/bot command=/usr/bin/python3 /home/bigbro/botbot.py autostart=true autorestart=true stderr_logfile=/var/log/bot.err.log stdout_logfile=/var/log/bot.out.log
To periodically launch the send script, you could use cron, but for reasons of consistency, I also run it through the supervisor and this bash script:
#!/bin/bash while true; do python3 sender.py ; sleep 30; done;
Result
Everything works exactly as it was intended:
Source: https://habr.com/ru/post/341678/
All Articles