4006

PIR-Sensor triggerd alarm sensor that gives local MP3-Alarm and sends an Alarm-eMail

An ESP8266 controls the built-in MP3 player module, some NeoPixel flash LEDs and a relay as soon as a PIR motion detector detects a movement.
 A local voice message is played and an alarm email is sent.

 The web interface allows you to switch the system on and off when you are standing outside the front door and shows the status of the system with animated GIFs. 
 Used hardware:
 - ESP8266 WEMOS D1 Mini
 - PIR motion detector
 - MP3 doorbell module with message e.g: "Police have been notified"
 - 3 NeoPixel LEDs for status and alarm flash
 - Relay for an external dashcam or other triggering


 The settings are saved for the next reboot.
 Programming is based on a BASIC-Script and  ANNEX-WiFi-RDS for any ESP8266-Controler-module (e.g.: Wemos D1 Mini). 
The program text is currently still somewhat German in the variable names and comments   If someone is interested I can change this :-) 

The BASIC code for the ESP8266 is created very easily with ANNEX WiFi RDS and looks like this
   
'##############################################################
' A l a r m a n l a g e 
VERSION$ = "V1.05"
' 11/2019  Peter.Neufeld@gmx.de   min:ANNEX_1.39b6
'
' - ESP8266-Module: WEMOS-D1-Mini
' - 3 Neopixel an D4
' - MP3-Player Puls-output an D6
' - PIR motion detector HC-SR501 on D5
'
' # Detects movement in front of the module (PIR sensor)
' and then triggers alarm actions: 
' -- RELAY CONTACT for 5 minutes (activates external camera with +5V)
' -- acoustic signal of the MP3 module (pin D6)
' -- Alarm email 
' -- Light pulses on the neopixel LEDs
' -- 15s after PIR alarm again MP3 output

' # Renewed PIR alarm extends Dashcam runtime
' # Starts after a power failure in the last system status 

'GPIO-Mapping auf PIN-Label der WEMOS- und NodeMCU-Boards
D0=16:  D1= 5:  D2= 4:  D3= 0:  D4=2: D5=14
D6=12:  D7=13:  D8=15:  D9=3:  D10=1
toggle = 0
m_alt=0
AUFNAHMEZEIT = 300  ' Countdown-Sekunden für Dascam-Relais
AUFNAHMEZEIT = 30  ' TEST 
MP3_nochmal  = 15  ' MP3 nach x Sek nochmals starten
m_to$       = "xxx.xxxxx@me.com"  'Adressat für die Alarm-eMails

'PIN für MP3-Player-Trigger
pin.mode D6, output
pin(D6)=0

'Relais für Dashcam AUS
pin.mode D7, output
pin(D7)=0
RELAIS_COUNTDOWN = 0 

'!!! NeoPixel-Data-output ist IMMER an D4=GPIO2!!!
NEO.setup 3   '3 Stück kascadierte NeoPixel-LEDs
gosub blink_IP
neo.strip 0,2, 0,2,0 'grün

'Modus beim Starten
STATUSFILE$ = "/ALARM.txt"
if file.exists(STATUSFILE$) = 1 then
' AN
  LED1_STATUS   = 0 'LED rot
  ANLAGENMODUS$ = "Bewegungsmelder ist AN"
  gosub           PIRSENSOR_ON
else
' AUS
  LED1_STATUS   = 1 'LED grün
  ANLAGENMODUS$ = "Bewegungsmelder ist AUS"
  gosub           PIRSENSOR_OFF
endif
t$            = time$
m_text$       = "Bewegungsmelder hat ausgelöst."

onHtmlReload  web_page
onhtmlchange  web_page
gosub         web_page

' damit ein Programmcrash nicht die Anlage stoppen kann
option.WDT 9000 ' set the WDT at 9 second

' ########################
'Hauptroutinen mit Timer einmal pro Sekunde starten
TIMER0 1000, MAIN_ROUTINE
' ########################
wait
end

'##############################################################
'UNTERPROGRAMME################################################
'##############################################################
MAIN_ROUTINE:

t$ = time$

'Das Dashcam-Relais bleibt nach Alarm für 300s an
if RELAIS_COUNTDOWN > 0 then
  RELAIS_COUNTDOWN = RELAIS_COUNTDOWN -1
else
  Pin(D7)= 0   'RELAIS AUS
  'wlog "Dashcam-Relais AUS"
endif    

'Mp3-Alarm  15s nach PIR-Auslösung  nochmals wiederholen
if RELAIS_COUNTDOWN = (AUFNAHMEZEIT - MP3_nochmal) then
 gosub MP3_ALARM
endif

if RELAIS_COUNTDOWN = 1 then
 gosub WEB_PAGE
endif

option.WDTreset             'reset watchdogtimer

'toggle= 1-toggle


'm=millis -m_alt
'm_alt = millis
'wlog "millis----:";str$(m)

return

'##############################################################
WEB_PAGE:
cls
autorefresh 1000
A$ = ""
A$ = A$ + |<!DOCTYPE html><html><body><style>|
A$ = A$ + |body {background-color: lightgrey;}|
A$ = A$ + |p {font-size:24px;}|
A$ = A$ + |</style>|
a$ = A$ + "<center><h1>- ALARMANLAGE -</h1>"
a$ = a$ + "<h5>-Version " + VERSION$ +"- </h5>"
a$ = a$ + textbox$(t$,"cssTB") + "<br><br>"
a$ = a$ + "<br>"+ textbox$(ANLAGENMODUS$,"cssTB1") 
a$ = a$ + "<br><br>"
a$ = a$ + BUTTON$(" A N / A U S ",ALARM_TOGGLE,"cssBT")
a$ = a$ + "<br>"

if RELAIS_COUNTDOWN = 0 and LED1_STATUS = 1 then
'  a$ = a$ +|<img src="http://neufeld.bplaced.net/Hund1.gif" alt="mueder Hund" />|
  a$ = a$ +|<img src="http://neufeld.bplaced.net/Hund5.gif" alt="Welpe" width="150"/>|
endif


if RELAIS_COUNTDOWN > 1 then
  a$ = a$ + "ALARM!<br>Eine Bewegung wurde erkannt!<br>" 
'  a$ = a$ +|<img src="http://neufeld.bplaced.net/Hund3.gif" alt="laufender Hund" />|
  a$ = a$ +|<img src="http://neufeld.bplaced.net/Hund4.gif" alt="bellende Dogge" />|
  a$ = a$ + "<br>Die DashCam zeichnet daher noch auf:<br>"+ textbox$(RELAIS_COUNTDOWN,"cssTB") 
else 
  if LED1_STATUS = 0 then 
    a$ = a$ +|<img src="http://neufeld.bplaced.net/Hund2.gif" alt="zwei Doggen" width="250" />|
    a$ = a$ + "<h3>Derzeit ist alles OK</h3>" 
  endif  
endif

a$ = a$ + cssid$("cssTB"," width:200px;height:2em; font-size:1.5em;text-align:center; background-color:greyn")
a$ = a$ + cssid$("cssTB1"," width:310px;height:2em; font-size:1.5em;text-align:center; background-color:"+ bgcol$)
a$ = a$ + cssid$("cssBT"," width:310px;height:2em; font-size:1.8em; border-radius:1.4em; padding:.5em; text-align:center")

html a$
a$ = ""
return

'##############################################################
ALARM_TOGGLE:
' Schaltet die Reaktion auf den Bewegungsmelder aus/an.
' Wird vom AN/AUS-Button aus dem Webinterface aufgerufen
LED1_STATUS= 1 - LED1_STATUS 'Webpage LED1 rot/gruen umschalten

'Analgenmodus umschalten
IF LED1_STATUS = 0 then 
  ANLAGENMODUS$="Bewegungsmelder ist AN"
  neo.strip 0,2, 150,0,0
  gosub PIRSENSOR_ON
  FILE.SAVE STATUSFILE$, "Wenn diese Datei vorhanden, dann beim PRG-Start auf ALARM gehen"
  neo.strip 0,2, 2,0,0 'schwach rot
else 
  ANLAGENMODUS$="Bewegungsmelder ist AUS"
  neo.strip 0,2, 0,150,0
  gosub PIRSENSOR_OFF
  if file.exists(STATUSFILE$)=1 then r=file.delete(STATUSFILE$)
  neo.strip 0,2, 0,2,0 'schwach grün
  RELAIS_COUNTDOWN = 0 
endif
gosub WEB_PAGE
'refresh
return


'##############################################################
MP3_ALARM:
pin(D6)=1
pause 50
pin(D6)=0
wlog "MP3_ALARM"
return

'##############################################################
PIR_PULS_ERKANNT:
' wird als Interrupt sowohl bei steigender, 
' als auch fallender Flanke des PIR-Sensors aufgerufen!!
if pin(D5) = 0 then return   ' Fallende Flake ignorieren
wlog  "PIR-Sensor hat ausgelöst:",time$
gosub ALARMACTION
Return

'##############################################################
PIRSENSOR_ON:
pin.mode D5, input   ' set D5 as input
interrupt D5, PIR_PULS_ERKANNT  ' set interrrupt on D5
bgcol$        = "red" 'füer cssstyle
wlog "PIRSENSOR_ON"
return

'##############################################################
PIRSENSOR_OFF:
pin.mode D5, input   ' set D5 as input
interrupt D5, OFF  ' disable interrrupt 
bgcol$        = "green"
wlog "PIRSENSOR_OFF"
return

'##############################################################
ALARMACTION:
'was soll bei Alarm gemacht werden?
'
gosub MP3_ALARM
gosub RELAIS_AN   'Relaiskontakt für externe Dashcam AN
gosub WEB_PAGE    'Inhalte aktualisieren

for i= 1 to 6
  neo.strip 0,2, 250,0,250
  pause 200
  neo.strip 0,2, 2,0,0 'schwach rot
  pause 200
next i

gosub MAIL_ALARM

return


'##############################################################
RELAIS_AN:
' Schaltet das RELAIS an D7 AN
' wird nach 5 Minuten wieder abgeschaltet (relais_countdown)
pin.mode D7, output
pin(D7)=1
wlog "Dashcam-Relais AN"
RELAIS_COUNTDOWN = AUFNAHMEZEIT

return



'##############################################################
blink_IP:
' Blinkt das letzte Octet der IP ; 0 = 10Blinks

' Falls noch keine IP-Adr bezogen wurde
while wifi.status <> 3 
neo.strip 0,2, 0,00,10
  pause 500  
neo.strip 0,2, 0,00,00
  pause 500  
wend

octet = 4   ' total num of octets in the IP address
localIP$ = word$(ip$,1)
for pos = 1 to len(localIP$)
  digitchr$ = mid$(localIP$,pos,1)
  if digitchr$ = "." then  'increment octet count
    octet = octet - 1
  else
    if octet > 1 goto Skip 'only want the last octet
    'roter Trenner zwischen den Ziffern
    neo.strip 0,2, 5,00,0
    pause 200
    neo.strip 0,2, 0,00,0
    pause 500
    if digitchr$ = "0" then digit = 10 else digit = val(digitchr$)
    'grünes Blinken der einzelnen  Ziffer 
    for count = 1 to digit
        neo.strip 0,2, 0,20,0
        pause 100
        neo.strip 0,2, 0,00,0
        if count = 5 then pause 200
        pause 350
    next count
    pause 800
  endif
Skip:
next pos
return

'##############################################################
mail_alarm:
m_konto$    = "alarm@xxxxx.de"
m_passwort$ = "xxxxx"
m_server$   = "mail.smtp2go.com"
m_port      = 465          '465 für smtp2go erforderlich!!
m_to$       = "peter.xxxxxx@xxxxx.com"'
m_subject$  = "ALARM_" + date$ + "_" + time$
m_subject$  = REPLACE$(m_subject$,":","-") 
' m_text$ kann den variablen textbody enthalten
m_message$  = "ALARM " + DATE$ + " " + TIME$ + " "+ m_text$

EMAIL.SETUP m_server$, m_port, m_konto$, m_passwort$
'EMAILASYNC(m_konto$, m_to$, m_subject$, m_message$)
r=EMAIL(m_konto$, m_to$, m_subject$, m_message$)

m_konto$    = ""
m_passwort$ = ""
m_server$   = ""
m_port      = 465          '465 für smtp2go erforderlich!!
'm_to$       = ""
m_subject$  = ""
m_message$  = ""
if r = 1 then wlog "email gesendet"
if r = 0 then wlog "email konnte NICHT gesendet werden!"

return