Decode email body from imap email content sensor

I have a template that is able to look at the email body. Each time I have motion in my security camera system I send myself an email to an email account that was set up solely to receive these emails. I have an imap email content sensor. I use a template to parse the body for the camera number where motion occurred. Unfortunately, the body is encoded in Base64. I want to use python to decode this information. However, I see that templates cannot import the Base64 library nor can a Python Script. I have been able to get the decode to work by copying the body data from my sensor and pasting into a python program I wrote (that imports Base64). I cannot determine a way I can access that program from a template or a Home assistant python script. I have a background in javascript and jquery so I know my way around that language. I know very little python and am learning that Homeassistant has a lot of power built in but it takes forever to determine the correct approach. I have seen several topics on this subject but none that I have seen helps me resolve this issue.

Here is my template:

- id: test parse email body
  alias: test parse email body using template
  trigger:
    entity_id: sensor.backyard_motion
    platform: state
    to: Alert
  # condition:
    # condition: sun
    # after: sunset
  action:
    service: light.turn_on
    data_template: 
      entity_id: >
        {% if is_state("sensor.backyard_motion", "Alert")%}
          {% set test = states.sensor.backyard_motion.attributes.body %}
          {% set mylist = test.split(":") %}
          {% set myalarm = mylist[2] %}
          {% if myalarm[1] == "3" %}
            light.level_8       
          {% elif myalarm[1] == "2" %}
            group.outside_courtyard_lights
          {% elif myalarm[1] == "1" %}
            light.level_7
          {% endif %}
        {% endif %}
      brightness: 120

Here is my python code to decode the body:

#!/usr/bin/python
import base64

decodedstr = base64.b64decode(email_body)

# I cut and paste the email body from the imap sensor into "email_body" 
# I don't know how to access the email body

Here is the info in the email body I need, all I need is the Alarm Input channel No:

Alarm: Motion Detect
Alarm input channel No.: 1
Alarm start time(D/M/Y H:M:S): 1/6/2018 17:44:44
Alarm device name: LNR6108

After 3 days, I am brain dead and cannot determine how to get the template and python code to work together in HA.

I have worked several days on this and cannot find a solution. Can anyone help me with this? Thanks in advance.

Did you have any look with this
I’m trying to get my smart alarm to send an email and have HA trigger an automation based on a word on the body of the email, but it come back with a string of characters.

I’m hoping what you are trying to achieve will resolve my issue too.

I did have luck with this. I gave up on templates and python script and ended up coding as an appdaemon app using python because this approach enabled the importing of the base64 library used to decode the body.

My imap sensor:

  - platform: imap_email_content
    name: 'Backyard Motion'
    server: imap.gmail.com
    port: 993
    username: [email protected]
    password: !secret gmail_password
    senders:
      - [email protected]

I set up a unique gmail account to receive the emails from my NVR (Network Video Recorder). I have 3 cameras. When motion is detected from any camera, it sends the email in the following format:

[email protected]
1:31 PM (5 minutes ago)
to me

Alarm: Motion Detect
Alarm input channel No.: 1
Alarm start time(D/M/Y H:M:S): 13/6/2018 13:32:24
Alarm device name: LNR6108

When the IMAP sensor reads the email, it is coded in base64 encoding and looks like:

body: QWxhcm06IE1vdGlvbiBEZXRlY3QgDQpBbGFybSBpbnB1dCBjaGFubmVsIE5vLjogMSAgDQpBbGFy
bSBzdGFydCB0aW1lKEQvTS9ZIEg6TTpTKTogMTMvNi8yMDE4IDEzOjM4OjU2DQpBbGFybSBkZXZp
Y2UgbmFtZTogTE5SNjEwOA0K

from: [email protected]
subject: Alert
friendly_name: Camera Motion Detector
date: Wed, 13 Jun 2018 13:38:57 +0800

The body is garbage and needs to be decoded:
Here is my code:

import appdaemon.plugins.hass.hassapi as hass
import base64


class motion_detect(hass.Hass):
    def initialize(self):
        self.level_7 = None
        self.level_11 = None
        self.camera_3_handle = None
        detected_by_camera = ""
        self.listen_state(self.motion_detected,"sensor.backyard_motion", new="Alert")
    def motion_detected(self, entity, attribute, old, new, kwargs):
        if self.sun_down():
#        if self.sun_up():
            mystate = self.get_state("sensor.backyard_motion")
            email_body = self.entities.sensor.backyard_motion.attributes.body
            mybody = base64.b64decode(email_body)
            mylist = str(mybody).split(':')
            myalarm = mylist[2]
            detected_by_camera = myalarm[1]
            #backyard porch
            if detected_by_camera == "3": 
                self.set_state("sensor.backyard_motion", new = "off")
                self.turn_on("light.level_8", brightness = "120")
                self.cancel_timer(self.detected_by_camera_3_handle)                                
                self.camera_3_handle = self.run_in(self.timer_handler, 60, myentity = "light.level_8")
                self.log(self.get_state("light.level_8", attribute='friendly_name') + ", turned on due to motion - line 30")
            # courtyard light                
            elif detected_by_camera == "2": 
               if self.now_is_between("sunset + 02:00:00", "sunrise"):
               #if self.now_is_between("sunrise", "sunset"):
                    self.set_state("sensor.backyard_motion", new = "off")
                    self.turn_on("light.level_11", brightness = "120")
                    self.cancel_timer(self.level_11) 
                    self.level_11 = self.run_in(self.timer_handler, 60, myentity = "light.level_11" ,timer_handle = "light2")
                    self.log(self.get_state("light.level_11", attribute='friendly_name') + ", turned on due to motion - line 39")                
            # middle garage                
            elif detected_by_camera == "1":
                self.set_state("sensor.backyard_motion", new = "off")                
                self.turn_on("light.level_7", brightness = "120")
                self.cancel_timer(self.level_7)                 
                self.level_7 = self.run_in(self.timer_handler, 60, myentity = "light.level_7")
                self.log(self.get_state("light.level_7", attribute='friendly_name') + ", turned on due to motion - line 48")                
            else: self.log("problem in if then else in program 'backyard_motion_detect'")
            self.set_state("sensor.backyard_motion", new = "off")
            self.notify("Motion detected from camera " + detected_by_camera)
            detected_by_camera = ''
        else: self.log("Sun is not down")
  
    def timer_handler(self, kwargs):
        self.turn_off(kwargs['myentity'])
        self.log(self.get_state(kwargs['myentity'], attribute='friendly_name') + ", turned on due to motion, is now off")
        self.notify(self.get_state(kwargs['myentity'], attribute='friendly_name') + ", turned on due to motion, is now off") 

This appdaemon code, parses the body to get to the camera that saw the motion. For example:

            email_body = self.entities.sensor.backyard_motion.attributes.body
            mybody = base64.b64decode(email_body)
            mylist = str(mybody).split(':')
            myalarm = mylist[2]
            detected_by_camera = myalarm[1]
            #backyard porch
            if detected_by_camera == "3": 

Let me know if you have questions.

Jim

1 Like

Oh I have some many questions. I’ve zero experience in python, but would love to get this set up.
I’m having a hikvision system installed friday which plays nicely with HA. Therefore i would like lights to activate based on motion detection, only if my alarm in on.

This is where your script comes in

Could you give me some pointers on how to start?

The script that I provided tells a lot. I suggest you study the code with python language at your side to determine what it is doing. Do you have any programming experience?

Not really, looks like I’ll be buying a for dummies book :slight_smile:

Sorry, I can’t help you learn Python, I am just a Python novice myself, but I have over 40 years programming experience in many other languages so it was fairly easy for me to learn to do what I had to do in Python. Good luck!

1 Like

Sorry to bother you again.

are you adding anything to your app.yaml or is it all picked up from the python script you posted?

No bother. Here is what is in my apps.yaml:

camera_motion_detect:
  module: camera_motion_detect
  class: motion_detect

Let me know if you need anything else.

hi,
could you please help me

how do i get to capture the word after KP, here is my email body

Yale Home Notification

Dear [email protected],

An event has been detected by your alarm:

2018-06-13 19:01:58 Area:1 User:David KP Disarm from Account:xxxxx

You want to capture “Disarm” only?

What are the values of the words after KP? What does KP mean?

hi yes
i have three notifications
Disarm
Home Arm
Fully Armed

ive been playing around and have the below partly working

    import appdaemon.plugins.hass.hassapi as hass
    import base64


class yale_status(hass.Hass):
    def initialize(self):

        self.listen_state(self.motion_detected,"sensor.yale", new="Yale Home Notification")
    def motion_detected(self, entity, attribute, old, new, kwargs):
            mystate = self.get_state("sensor.yale")
            email_body = self.entities.sensor.yale.attributes.body
            mybody = base64.b64decode(email_body)
            mylist = str(mybody).split()

            #House Armed
            if 'Arm' in mylist: 
                self.set_state("sensor.yale", new = "off")
                self.turn_on("input_boolean.yale_alarm")

            # House Disarmed                
            elif 'Disarm' in mylist:
                self.set_state("sensor.yale", new = "off")
                self.turn_off("input_boolean.yale_alarm")              

            else: self.log("problem in if then else in program 'yalesensor'")
            self.set_state("sensor.yale", new = "off")

edit
I’m a dumbass the word home appears more than once, I forgot to remove it when running test.

Arm triggers on
Disarm triggers off

cheers

KP stands for keypad

So, are you ok or do you still need help?

I’m okay
I have it working thank you for the original code.

Great! Have a good day!

Hi,

I think this is what I have been looking for… I too have a dvr system that sends emails as an alert for motion, while the emails are in plain text I still need a way of pulling the camera number that detected the motion from the email body.

I’m currently using a binary sensor to detect ftp uploads on motion detection (using inotify), its a little slow and there is no way to distinguish which camera detected motion.

I have had some partial success with using the template editor but its a little beyond me can you possibly give me some pointers?

ta
Scott

Sure, could you take a picture of an email and post it? Are you familiar with Python? Appdaemon coding? What is the model of your NVR, mine is in the LNR6100 Series.

hi,

I am not familiar with python coding unfortunately and I’ve been struggling to install Appdaemon for the last two days (for use with hadashboard).

The DVR is model Sansco 1080N 4 channel.

email image attached… the DVR sends one at the start of the motion “DetectStart” and one at the end “DetectEnd”.

I use Hassbian currently, because I need to use inotifywait to watch for ftp uploads for motion, up until the recent switch I was using hass.io, which is a lot simpler for a non python guy like me but you can’t use scripts with it.

thanks
Scott

Let me know when you have appdaemon working. I have created some python code that will find the camera number where motion was detected. We can then put the pieces together to get you up and running. Also, rather than a picture of your email, cut and paste the body in this thread so I can test with actual data.
With dummied data (email_body below), I created the following code:

#!/usr/bin/env python
import appdaemon.plugins.hass.hassapi as hass
import base64
import string

class pavey(hass.Hass):
    def initialize(self):
        email_body = "Alarm event: MotionDetectEnd  Alarm Begin Time: 2018-06-21 13:24:34 Alarm input channel No: CAM02(2)"
        y = email_body.find('DetectEnd')
        if y == -1:
            self.log("DetectEnd not found")
        else:
            z =  email_body.split('(')
            camera_index = z[1]
            camera_where_motion_detected = camera_index[0]
            self.log(camera_where_motion_detected)

wonderful stuff and much appreciated thank you, I’m struggling on with Appdaemon, permission and ssl issues are hampering any progress and I may go back to hass.io to install Appdaemon assuming your script will work under it?

Emails as follows…

Alarm event: Motion DetectStart
Alarm Begin Time: 2018-06-21 19:45:13
Alarm input channel No.: BACK GARDEN(1)
Alarm device name: LocalHost
Sender IP address: 192.168.1.197

Alarm event: Motion DetectEnd
Alarm Begin Time: 2018-06-21 19:45:15
Alarm input channel No.: BACK GARDEN(1)
Alarm device name: LocalHost
Sender IP address: 192.168.1.197

Alarm event: Motion DetectStart
Alarm Begin Time: 2018-06-21 19:46:39
Alarm input channel No.: FRONT GARDEN(2)
Alarm device name: LocalHost
Sender IP address: 192.168.1.197

Alarm event: Motion DetectEnd
Alarm Begin Time: 2018-06-21 19:46:41
Alarm input channel No.: FRONT GARDEN(2)
Alarm device name: LocalHost
Sender IP address: 192.168.1.197

these are the sets of email that are received for the two cameras I have connected.

ta
Scott