Telegram bot doorbell - Raspberry Pi - python

I'm new to python and raspberry, I would like to make a smart doorbell controlled by a bot on telegram. The doorbell in question has a pir sensor that sends a video over telegram every time its triggered. I would like to have the messages I send to the bot read through the speakers.
But I have a problem with the while true loop of the sensor and the handle (msg) function of telepot, I need to take the chat_id variable out of the handle function to use it in the other functions but I can't. I am attaching the complete code:
import telepot
from picamera import PiCamera
import RPi.GPIO as GPIO
import time
from time import sleep
import datetime
from telepot.loop import MessageLoop
from subprocess import call
import sys
import random
import pyttsx3
# setup sensori
PIR = 4
camera = PiCamera()
camera.resolution = (680, 480)
camera.framerate = 25
camera.rotation = 180
# setup pin
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIR, GPIO.IN)
# variabili movimento
motion = 0
motionNew = 0
# telegram bot
def handle(msg):
global telegramText
global chat_id
chat_id = msg['chat']['id']
telegramText = msg['text']
print('Messaggio ricevuto! ' + str(chat_id) + telegramText)
# start engine per leggere i messaggi
engine = pyttsx3.init()
rate = engine.getProperty('rate') # variabile per cambiare velocita
engine.setProperty('rate', rate-50) # velocita voce
voice_id = 'italian'
engine.setProperty('voice', voice_id)
engine.say(telegramText)
engine.runAndWait()
if telegramText == '/start':
bot.sendMessage(chat_id, 'Sicurezza del perimetro attiva, sei protetto!')
# connessione bot telegram
bot = telepot.Bot('####')
bot.message_loop(handle)
# definizione funzione principale movimento
def main():
global chat_id
global motion
global motionNew
if GPIO.input(PIR) == 1:
print("Movimento rilevato!")
motion = 1
if motionNew != motion:
motionNew = motion
sendNotification()
elif GPIO.input(PIR) == 0:
motion = 0
if motionNew != motion:
motionNew = motion
def sendNotification():
global chat_id
bot.sendMessage(chat_id, 'ATTENZIONE! Qualcuno è alla porta!')
filename = "./video_" + (time.strftime("%y%b%d_%H%M%S"))
camera.start_recording(filename + ".h264")
sleep(10)
camera.stop_recording()
command = "MP4Box -add " + filename + '.h264' + " " + filename + '.mp4'
print(command)
call([command], shell=True)
bot.sendVideo(chat_id, video=open(filename + '.mp4', 'rb'))
print('Attendo 20 secondi')
time.sleep(20)
# definizione interrupt
def end_security():
print('End')
# check continuo sensore pir
try:
while True:
main()
except KeyboardInterrupt:
end_security()
I get an error in this line:
bot.sendMessage(chat_id, 'ATTENZIONE! Qualcuno è alla porta!')
error:
NameError: name 'chat_id' is not defined
How can I manage it? Thank you

I think the problem is that when you call sendNotification() before handle() has been called then chat_id has not been set by anything so is undefined.
If you change your main loop code to the following, then you shouldn't get the error, since chat_id will be defined to a value at the beginning of the program.
try:
chat_id=999999999
while True:
main()
However, I'm not sure what you want chat_id to be set to when you call sendNotification() from the main() function since you don't have a message to take it from? Do you really need chat_id to be a global. It may be better to pass the chat id into sendNotification() as a parameter.

Related

Where can I set a default audio input in Pyaudio?

I work on a sequencial started audio recorder on Raspberry pi, my problem is the following:
I tried several ways ,I described under the code, to get Pyaudio open a stream after the second time it recorded and saved the stream in .wav format.
in the second run it wont start over opening the stream and gives me this error,
I simply don't get why the default input device only gets accepted once is it my still used by the last stream even If I terminated it?
I am using an external USB as input since raspberry still has no option to take Mic. input.
I also took .open() and tried every possible input device I found.
Traceback (most recent call last):
File "/home/fabian/Documents/Zusammenschluss_REC()_mit_Interrupt_BACKUP1.py", line 122, in <module>
stream = audio.open(format= pyaudio.paInt16, channels = 1, rate=44100, input= True, frames_per_buffer=1024)
File "/home/fabian/.local/lib/python3.9/site-packages/pyaudio.py", line 754, in open
stream = Stream(self, *args, **kwargs)
File "/home/fabian/.local/lib/python3.9/site-packages/pyaudio.py", line 445, in __init__
self._stream = pa.open(**arguments)
OSError: [Errno -9996] Invalid input device (no default output device)
#imports to be made:
import RPi.GPIO as GPIO
import time
import os
import sys
import signal
import datetime
import pyaudio
import wave
#variables to be defined:
BUTTON_GPIO = 16
LED_REC_GPIO = 20
LED_ON_GPIO = 21
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
global TIME_LAST_PRESSED
TIME_LAST_PRESSED = time.time()
global TIME_LAST_SWITCHED
TIME_LAST_SWITCHED = time.time()
global timeout
timeout = 1
TIME_MIN = 0.2
TIME_MAX = 0.6
Loop = True
REC = False
audio = pyaudio.PyAudio()
parent_dir = "/home/fabian/Dokumente/Speicherordner_Audiofiles"
global person
person = "fabian"
#Definition of functions:
def signal_handler(sig, frame):
GPIO.cleanup()
sys.exit(0)
def button_pressed_callback(channel):
print("Button has been pressed")
global TIME_LAST_PRESSED
global TIME_LAST_SWITCHED
global REC
print("CALLBACK activated, now checking sequence")
x = time.time() - TIME_LAST_PRESSED
print(x)
if x > TIME_MIN and x < TIME_MAX:
print("Sequence succeded! Sequence time:" + str(x))
y = time.time() - TIME_LAST_SWITCHED
if timeout < y:
TIME_LAST_SWITCHED = time.time()
REC = not REC
print("REC has now the value off:" + str(REC))
TIME_LAST_PRESSED = time.time()
#setup of GPIO:
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(LED_REC_GPIO, GPIO.OUT)
GPIO.setup(LED_ON_GPIO, GPIO.OUT)
GPIO.add_event_detect(BUTTON_GPIO, GPIO.FALLING, callback = button_pressed_callback, bouncetime = 100)
signal.signal(signal.SIGINT, signal_handler)
#setup of savingpath:
saving_path = parent_dir + "/" + person
if os.path.isfile(saving_path):
os.makedirs(saving_path)
#"Main" loop:
GPIO.output(LED_ON_GPIO, GPIO.HIGH)
while Loop:
if REC:
stream = audio.open(format= pyaudio.paInt16, channels = 1, rate=44100, input= True, frames_per_buffer=1024)
frames = []
REC_TIME = time.time()
GPIO.output(LED_REC_GPIO, GPIO.HIGH)
while REC:
data = stream.read(1024)
frames.append(data)
GPIO.remove_event_detect(BUTTON_GPIO)
stream.stop_stream()
stream.close()
audio.terminate()
now = datetime.datetime.now()
REC_TIME = time.time()-REC_TIME
date =str(now.day) + "." + str(now.month) + "." + str(now.year) + " " + str(now.hour) + ":" + str(now.minute) + " "
os.makedirs(saving_path +"/"+ date + str(REC_TIME))
sound_file = wave.open(saving_path + date + str(REC_TIME), "w")
sound_file.setnchannels(1)
sound_file.setsampwidth(audio.get_sample_size(pyaudio.paInt16))
sound_file.setframerate(44100)
sound_file.writeframes(b"".join(frames))
sound_file.close()
GPIO.add_event_detect(BUTTON_GPIO, GPIO.FALLING, callback = button_pressed_callback, bouncetime = 100)
else:
GPIO.output(LED_REC_GPIO, GPIO.LOW)
if Loop == False:
print ("cleanup")
GPIO.cleanup
I created .asoundrc set the default card and device after I looked it up with aplay -l and arecord -l
I changed the default in alsa.conf
First run everything works just fine, second time in the recording loop it won't take the input device.

Telegram Bot with schedule tasks

I'm just starting to discover how to build a bot with python. I'm trying to send a message at certain time. I read a lot of example, I read the documentation regarding modul_schedule function but I can't fix this issue...
import config
import telebot
import requests
import schedule
import time
from my_parser import parse
from bs4 import BeautifulSoup as BS
bot = telebot.TeleBot(config.token)
r = requests.get('https://example')
html = BS(r.content, 'html.parser')
for el in html.select('#content'):
t_min = el.select('.temperature .min')[0].text
t_max = el.select('.temperature .max')[0].text
min_text = el.select('.wDescription .description')[0].text
t_test = el.select('.wDescription .description')[0].text
response = requests.get(url='https://example')
data = response.json()
btc_price = f"B: {round(data.get('btc_usd').get('last'), 2)}$"
#bot.message_handler(commands=['start', 'help'])
def main(message):
bot.send_message(
message.chat.id, t_min + ', ' + t_max + '\n' + min_text + '\n' + parse() + '\n' + btc_price)
if __name__ == '__main__':
bot.polling(none_stop=True, interval=0)
schedule.every(1).seconds.do(main)
while True:
schedule.run_pending()
time.sleep(1)
I would like the bot send message every morning with temperature on to a channel. I did not find any clues on how to use the function correctly.
I use this library.
Example of my code.
import aioschedule as schedule
async def some_fun():
pass
async def scheduler():
schedule.every().day.at("09:00").do(some_fun())
while True:
await schedule.run_pending()
await asyncio.sleep(2)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.create_task(scheduler())
main()

bot terminated by other getUpdates request make sure that only one bot instance is running

Hello everyone In this module(telegram_interface.py) I have (send_msg) method which I need to call it in another modules, but whenever I try to import this module(telegram_interface) inside the other modules to call the send_msg method, I had the error that I'm calling getUpdates from more than one instance, is there away to avoid this to happen !
telegram_interface.py
import configparser
import telepot
import time
from database import Status
import datetime as dt
import place_orders as po
import requests
config = configparser.ConfigParser()
config.read("config1.ini")
bot_token = str(config["TelegramBot1"]["bot_token"])
my_chat_id = str(config["TelegramBot1"]["my_chat_id"])
bot111 = telepot.Bot(bot_token)
def time_now():
time = dt.datetime.now()
time = time.strftime("%H:%M:%S // %d-%m-%Y")
return time
# def send_msg(text):
# url = "https://api.telegram.org/bot"+bot_token + \
# "/sendMessage?chat_id="+my_chat_id+"&parse_mode=Markdown&text="
# http_request = url + text
# response = requests.get(http_request)
# return response.json()
def handle(msg):
user_name = msg["from"]["first_name"] + " " + msg["from"]["last_name"]
content_type, chat_type, chat_id = telepot.glance(msg)
if content_type == "text":
command = msg["text"]
if "/START" == command.upper():
bot111.sendMessage(chat_id,
"Welcome "+user_name+" in your Auto Trading Bot! \n command [/help] to get more information about the bot. ")
elif "/HELP" == command.upper():
bot111.sendMessage(chat_id,
"Available commands are: \n **[ON, OFF] - Control the bot. \n **[balance] - Get your free USDT balance.")
elif "ON" == command.upper():
Status.save_status(collection="Status",
status=command.upper(), time=time_now())
bot111.sendMessage(chat_id, "System is *Activated*.",
parse_mode="Markdown")
with open("log.txt", "a") as log_file:
log_file.write(
"System is Activated at : " + time_now() + "\n")
elif "OFF" == command.upper():
Status.save_status(collection="Status",
status=command.upper(), time=time_now())
bot111.sendMessage(chat_id, "System is *Deactivated*.",
parse_mode="Markdown")
with open("log.txt", "a") as log_file:
log_file.write("System is Deactivated at : " +
time_now() + "\n")
elif "BALANCE" == command.upper():
free_balance = po.get_usdt_balance()
bot111.sendMessage(chat_id,
"Your free balance is : *"+str(free_balance)+" USDT*", parse_mode="Markdown")
else:
bot111.sendMessage(chat_id,
"Unknown command, use [/help] to get more information.")
bot111.message_loop(handle)
while True:
time.sleep(20)
When you import any module in Python, it is being executed, for example let's imagine we have the following module print_hello.py:
print('hello world')
If you run it, it will print hello world. If you import this module:
import print_hello
it will print hello world too! So, if you import it multiple times, it will print hello world exactly that much times.
To avoid this, you need to simulate main entrypoint, edit print_hello.py:
if __name__ == '__main__':
print('hello world')
In this case, hello world will be printed only with running print_hello.py, but won't be printed if imported.
So, you should apply this to your lines of code:
bot111.message_loop(handle)
while True:
time.sleep(20)

Why is the AI repeating the function?

When I say "Friday" "take a screenshot" it takes a screenshot. Everything okay. But it repeats this function. It says "I took a screenshot of your main screen" and takes a screenshot again and again. It is only this function. I tried with other functions but there it repeats it only one time - that is an other problem to fix.
Main code:
import functions as FF
import speakandrecognizefunctions as SRF
import datetime
import pyautogui
WAKE_WORD = "friday"
USER = "user"
PATH = "C://MeineDirection"
def success():
print("Succesful")
def screenshot():
date = datetime.datetime.now()
filename = str(date).replace(":", "-") + "-screenshot.png"
img = pyautogui.screenshot()
img.save(f'{PATH}//screenshots//{filename}')
SRF.speak("I took a screenshot of your main screen " + USER)
while True:
text = SRF.takecommandbackground()
if text.count(WAKE_WORD) > 0:
SRF.speak("Im listening " + USER)
print("\nListening....")
text = SRF.takecommand()
SCREENSHOT_STRS = ["make a screenshot", "take a screenshot", "screenshot"]
for phrase in SCREENSHOT_STRS:
if phrase in text:
screenshot()
success()
Speech recognition code:
import pyttsx3
import speech_recognition as sr
import config
engine = pyttsx3.init('sapi5')
voices = engine.getProperty('voices')
engine.setProperty('voice', voices[1].id)
WAKE_WORD = "friday"
def speak(text):
engine.say(text)
engine.runAndWait()
def takecommand():
r = sr.Recognizer()
with sr.Microphone() as source:
#r.adjust_for_ambient_noise(source, duration=0.5)
audio = r.listen(source)
said = ""
try:
said = r.recognize_google(audio)
print(said)
except Exception as e:
speak("I didnt get that !!")
print(f"Exception. Say {WAKE_WORD} and try again " + str(e))
pass
return said.lower()
def takecommandbackground():
r = sr.Recognizer()
with sr.Microphone() as source:
r.adjust_for_ambient_noise(source, duration=0.3)
#print("Ready")
audio = r.listen(source, phrase_time_limit=4)
try:
# print("Recognizing....")
query = r.recognize_google(audio)
#print("user said : ", query)
# speak(query)
except Exception:
#print("Say that again please !! ")
return "none"
return query.lower()
Easy "take a screenshot" will trigger for "take a screenshot" & "screenshot"
Take out "screenshot" from SCREENSHOT_STRS and see what . If that works then you want to break the loop as #jasonharper suggested
You need to break the Loop, because it loops all the Time, or you clear the Text Var.

RFID scanner doesn't scan afterwards

I am very new to coding and I'm working on this project that I have no idea why is it not running as expected. I am sorry if I'm not posting this correctly because this is my first time posting on stackoverflow. Pardon my English if there's any point where I didn't explain it correctly.
This is a project supposed to be a security system one, where we work with RFID Scanner, Camera, LED, Servo and PIR Sensor.
The conditions are as, when the time is 7am to 11pm, the pir sensor would be off and when time is 11pm onwards to 7am in the morning, the PIR sensor and camera will be turned on. Where during anytime, as long as the number of people in the house is = 0 (determined by the RFID), the camera and PIR Sensor would turn on too.
I haven't got a chance to even test out my code's logic, because when I tried to run the code, an error occurs at the loop part. "Scan a registered card to skip registration" would print and "checkpoint" would print, but afterward the code just stops there. It is supposed to be listening to the RFID scanner to read for scans, but when I tapped my card on the RFID scanner there was no response. And my code just dies there. As I'm very new to coding and python, I don't know where the errors could be. Would appreciate the help given!!
import RPi.GPIO as GPIO
from time import sleep
import sys
import requests
from datetime import datetime
from mfrc522 import SimpleMFRC522 #RFID
import os
import pygame, sys
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from pygame.locals import *
import pygame.camera
width = 640
height = 480
#initialise pygame
pygame.init()
pygame.camera.init()
cam = pygame.camera.Camera("/dev/video0",(width,height))
no=0
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(24,GPIO.OUT) #LED
GPIO.setup(26,GPIO.OUT) #Servo
GPIO.setup(17,GPIO.IN) #PIR Sensor
current_time =datetime.now() #Current time
sleep(5)
reader = SimpleMFRC522() #RFID reader
auth = []
in_house =[]
p = open("presentlist.txt","a+")
p = open("presentlist.txt","r+")
present = 0
PIR_state =0
PWM=GPIO.PWM(26,50) #Set 50hz PWM output at GPIO26
PWM.start(12) #To edit to actual 3oclock (Locked)
fromaddr = "pythonprogramtest123#gmail.com" # change the email address accordingly
toaddr = "pythonprogramtest123#gmail.com" # Same email
#password: abcdefgpython
mail = MIMEMultipart()
mail['From'] = fromaddr
mail['To'] = toaddr
mail['Subject'] = "Attachment"
body = "Unusual movement detected"
print('Door Locked')
print("Hold card near the reader to register it in the database.")
print("Registration up to 10 cards")
print("Scan a registered card to skip registration")
for count in range (0,11):
print("checkpoint1")
id = reader.read_id()
id = str(id)
f = open("authlist.txt", "a+")
f = open("authlist.txt", "r+")
print("checkpoint2")
if f.mode == "r+":
auth=f.read()
if id not in auth:
f.write(id)
f.write('\n')
f.close()
pos = auth.count('\n')
print("New card with UID", id, "detected: registered as entry #",pos)
count = count +1
else:
number = auth.split('\n')
pos = number.index(id)
print("Card with UID", id, "already registered as entry #", pos)
count = 11
break
while (True):
id = reader.read_id()
id = str(id)
f = open("authlist.txt", "a+")
f = open("authlist.txt", "r+")
if current_time.hour >= 7 or current_time.hour <= 23 or present == 0: #awake or nobody in house
#RFID is on
if f.mode == "r+":
auth=f.read()
if id in auth and id not in in_house:
p.write(id)
p.write('\n')
p.close()
present = in_house.count('\n')
print("Recognition successful \n Allowing Access")
PWM.start(1) #Servo to actual 12 o clock position (Unlocking)
print("Door unlocked for 30 seconds. Tap once more to change to 1 minute")
if f.mode == "r+":
auth=f.read()
if id in auth:
print("Unlocking door for 1 minute")
sleep(60)
PWM.start(12) #To edit to actual 3oclock (Locked)
f.close()
else: #no tap detected
sleep(30)
PWM.start(12) #To edit to actual 3oclock (Locked)
f.close()
break
elif id in auth and id in in_house:
p.remove(id)
print("Recognition successful \n Allowing Access")
PWM.start(1) #Servo to actual 12 o clock position (Unlocking)
print("Door unlocked for 30 seconds. Tap once more to change to 1 minute")
if f.mode == "r+":
auth=f.read()
if id in auth:
print("Unlocking door for 1 minute")
sleep(60)
PWM.start(12) #To edit to actual 3oclock (Locked)
f.close()
else: #no tap detected
sleep(30)
PWM.start(12) #To edit to actual 3oclock (Locked)
f.close()
break
else:
print("Card not recognised \n Access Denied")
break
elif current_time.hour < 7 or current_time.hour > 23: #sleeping
id = reader.read_id()
id = str(id)
f = open("authlist.txt", "a+")
f = open("authlist.txt", "r+")
#RFID is on
if f.mode == "r+":
auth=f.read()
if id in auth:
print("Recognition successful \n Allowing Access")
PWM.start(1) #Servo to actual 12 o clock position (Unlocking)
print("Door unlocked for 30 seconds. Tap once more to change to 1 minute")
if f.mode == "r+":
auth=f.read()
if id in auth:
print("Unlocking door for 1 minute")
sleep(60)
PWM.start(12) #To edit to actual 3oclock (Locked)
else: #no tap detected
sleep(30)
PWM.start(12) #To edit to actual 3oclock (Locked)
break
else:
print("Card not recognised \n Access Denied")
break
#Camera
if GPIO.input(17): #read a HIGH i.e. motion is detected
#LED Blink
GPIO.output(24,1)
sleep(1)
GPIO.output(24,0)
sleep(1)
GPIO.output(24,1)
sleep(1)
GPIO.output(24,0)
if PIR_state==0:
print('detected HIGH i.e. motion detected')
PIR_state=1
#Camera
cam.start() #start
image = cam.get_image() #take pic
cam.stop()
no = no + 1
saved_img=pygame.image.save(windowSurfaceObj,'picture' + "{:03d}".format(no) + '.jpg')
#Thingspeak
print("Updating Thingpseak")
resp = requests.get("GET https://api.thingspeak.com/update?api_key=PQ44ZG5JR49ABODY&field1=0")
#Email
def sendMail(data):
mail.attach(MIMEText(body, 'plain'))
print (data)
dat='%s.jpg'%data
print (dat)
attachment = open(dat, 'rb')
image=MIMEImage(attachment.read())
attachment.close()
mail.attach(image)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(fromaddr, "abcdefgpython")
text = mail.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
else: #read a LOW i.e. no motion is detected
if PIR_state==1:
print('detected LOW i.e. no motion detected')
PIR_state=0
sleep(1)
print("...")
break
sleep(2)

Categories