# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import datetime
+import logging
import os
import smtplib
import socket
import settings
+from motioneye import _configure_settings, _configure_logging
-def send_mail(host, port, username, password, tls, to, subject, message):
- conn = smtplib.SMTP(host, port, timeout=getattr(settings, 'SMTP_TIMEOUT', 60))
+_configure_settings()
+_configure_logging()
+
+import config
+import tzctl
+
+
+messages = {
+ 'motion_start': 'Motion has been detected by camera "%(camera)s/%(hostname)s" at %(moment)s (%(timezone)s).'
+}
+
+subjects = {
+ 'motion_start': 'motionEye: motion detected by "%(camera)s"'
+}
+
+
+def send_mail(server, port, account, password, tls, to, subject, message):
+ conn = smtplib.SMTP(server, port, timeout=getattr(settings, 'SMTP_TIMEOUT', 60))
if tls:
conn.starttls()
- if username and password:
- conn.login(username, password)
+ if account and password:
+ conn.login(account, password)
- _from = username or 'motioneye@' + socket.gethostname()
+ _from = account or 'motioneye@' + socket.gethostname()
email = MIMEText(message)
email['Subject'] = subject
conn.quit()
+def format_message(subject, message, camera_id, moment):
+ format_dict = {
+ 'camera': config.get_camera(camera_id)['@name'],
+ 'hostname': socket.gethostname(),
+ 'moment': moment.strftime('%Y-%m-%d %H:%M:%S'),
+ }
+
+ if settings.LOCAL_TIME_FILE:
+ format_dict['timezone'] = tzctl.get_time_zone()
+
+ else:
+ format_dict['timezone'] = 'local time'
+
+ message = message % format_dict
+ subject = subject % format_dict
+ subject = subject.replace('\n', ' ')
+
+ message += '\n\n'
+ message += 'motionEye.'
+
+ return (subject, message)
+
+
def print_usage():
- print 'Usage: sendmail.py <to> <message>'
- print 'Environment: HOST, PORT, USERNAME, PASSWORD, TLD'
+ print 'Usage: sendmail.py <server> <port> <account> <password> <tls> <to> <msg_id> <camera_id> <moment>'
if __name__ == '__main__':
- if len(sys.argv) < 4:
+ if len(sys.argv) < 10:
print_usage()
sys.exit(-1)
- host = os.environ.get('SMTP_HOST', 'localhost')
- port = int(os.environ.get('SMTP_PORT', '465'))
- username = os.environ.get('SMTP_USERNAME')
- password = os.environ.get('SMTP_PASSWORD')
- tls = os.environ.get('SMTP_TLS') == 'true' or True
- to = sys.argv[1]
- subject = sys.argv[2]
- message = sys.argv[3]
+ server = sys.argv[1]
+ port = int(sys.argv[2])
+ account = sys.argv[3]
+ password = sys.argv[4]
+ tls = sys.argv[5].lower() == 'true'
+ to = sys.argv[6]
+ msg_id = sys.argv[7]
+ camera_id = sys.argv[8]
+ moment = sys.argv[9]
+
+ message = messages.get(msg_id)
+ subject = subjects.get(msg_id)
+ if not message or not subject:
+ logging.error('unknown message id')
+ sys.exit(-1)
+
+ moment = datetime.datetime.strptime(moment, '%Y-%m-%dT%H:%M:%S')
+ subject, message = format_message(subject, message, camera_id, moment)
- send_mail(host, port, username, password, tls, to, subject, message)
+ send_mail(server, port, account, password, tls, to, subject, message)
- print('message sent.')
+ logging.info('message sent.')
# enables rebooting after changing system settings (such as wifi settings or system updates)
ENABLE_REBOOT = False
+
+# the timeout in seconds to use when talking to a SMTP server
+SMTP_TIMEOUT = 60
'pre_capture': int(ui['pre_capture']),
'post_capture': int(ui['post_capture']),
- # motion notifications
- '@motion_notifications': ui['motion_notifications'],
- '@motion_notifications_emails': ui['motion_notifications_emails'],
-
# working schedule
- '@working_schedule': ''
+ '@working_schedule': '',
+
+ # events
+ 'on_event_start': ''
}
+ on_event_start = []
+
if 'brightness' in ui:
if int(ui['brightness']) == 50:
data['brightness'] = 0
max_val = min(max_val, 9999999)
data['ffmpeg_bps'] = int(ui['movie_quality']) * max_val / 100
+
+ if ui['motion_notifications']:
+ send_mail_path = os.path.join(settings.PROJECT_PATH, 'sendmail.py')
+ send_mail_path = os.path.abspath(send_mail_path)
+
+ emails = re.sub('\\s', '', ui['motion_notifications_emails'])
+
+ on_event_start.append('%(script)s %(server)s %(port)s %(account)s %(password)s %(tls)s %(to)s motion_start %%t %%Y-%%m-%%dT%%H:%%M:%%S' % {
+ 'script': send_mail_path,
+ 'server': ui['smtp_server'],
+ 'port': ui['smtp_port'],
+ 'account': ui['smtp_account'],
+ 'password': ui['smtp_password'],
+ 'tls': ui['smtp_tls'],
+ 'to': emails})
if ui['working_schedule']:
data['@working_schedule'] = (
ui['friday_from'] + '-' + ui['friday_to'] + '|' +
ui['saturday_from'] + '-' + ui['saturday_to'] + '|' +
ui['sunday_from'] + '-' + ui['sunday_to'])
+
+ if on_event_start:
+ data['on_event_start'] = '; '.join(on_event_start)
return data
'pre_capture': int(data['pre_capture']),
'post_capture': int(data['post_capture']),
- # motion notifications
- 'motion_notifications': data['@motion_notifications'],
- 'motion_notifications_emails': data['@motion_notifications_emails'],
-
# working schedule
'working_schedule': False,
'monday_from': '09:00', 'monday_to': '17:00',
'sunday_from': '09:00', 'sunday_to': '17:00'
}
+ on_event_start = data.get('on_event_start') or []
+ if on_event_start:
+ on_event_start = [e.strip() for e in on_event_start.split(';')]
+
# the brightness & co. keys in the ui dictionary
# indicate the presence of these controls
# we must call v4l2ctl functions to determine the available controls
max_val = data['width'] * data['height'] * data['framerate'] / 3
max_val = min(max_val, 9999999)
- ui['movie_quality'] = min(100, int(round(ffmpeg_bps * 100.0 / max_val)))
+ ui['movie_quality'] = min(100, int(round(ffmpeg_bps * 100.0 / max_val)))
+ for e in on_event_start:
+ if e.count('sendmail.py') and e.count('motion_start'):
+ e = e.split(' ')
+ if len(e) != 10:
+ continue
+
+ ui['motion_notifications'] = True
+ ui['smtp_server'] = e[1]
+ ui['smtp_port'] = e[2]
+ ui['smtp_account'] = e[3]
+ ui['smtp_password'] = e[4]
+ ui['smtp_tls'] = e[5].lower() == 'true'
+ ui['motion_notifications_emails'] = e[6]
+
+ break
+
working_schedule = data['@working_schedule']
if working_schedule:
days = working_schedule.split('|')
data.setdefault('ffmpeg_video_codec', 'msmpeg4')
data.setdefault('@preserve_movies', 0)
- data.setdefault('@motion_notifications', False)
- data.setdefault('@motion_notifications_emails', '')
-
data.setdefault('@working_schedule', '')
+ data.setdefault('on_event_start', '')
+
def _get_wifi_settings(data):
wifi_settings = wifictl.get_wifi_settings()
def _get_time_zone_symlink():
file = settings.LOCAL_TIME_FILE
+ if not file:
+ return None
for i in xrange(8): # recursively follow the symlinks @UnusedVariable
try:
def _get_time_zone_md5():
+ if settings.LOCAL_TIME_FILE:
+ return None
+
try:
output = subprocess.check_output('cd /usr/share/zoneinfo; find * -type f | xargs md5sum', shell=True)
makeTextValidator($('#imageFileNameEntry'), true);
makeTextValidator($('#movieFileNameEntry'), true);
makeTextValidator($('#emailAddressesEntry'), true);
+ makeTextValidator($('#smtpServerEntry'), true);
+ makeTextValidator($('#smtpAccountEntry'), true);
+ makeTextValidator($('#smtpPasswordEntry'), true);
/* number validators */
makeNumberValidator($('#streamingPortEntry'), 1024, 65535, false, false, true);
makeNumberValidator($('#eventGapEntry'), 1, 86400, false, false, true);
makeNumberValidator($('#preCaptureEntry'), 0, 100, false, false, true);
makeNumberValidator($('#postCaptureEntry'), 0, 100, false, false, true);
+ makeNumberValidator($('#smtpPortEntry'), 1, 65535, false, false, true);
/* time validators */
makeTimeValidator($('#mondayFrom'));
/* ui elements that enable/disable other ui elements */
$('#motionEyeSwitch').change(updateConfigUi);
$('#showAdvancedSwitch').change(updateConfigUi);
+ $('#wifiSwitch').change(updateConfigUi);
$('#storageDeviceSelect').change(updateConfigUi);
$('#autoBrightnessSwitch').change(updateConfigUi);
$('#resolutionSelect').change(updateConfigUi);
$('#preserveMoviesSelect').change(updateConfigUi);
$('#motionNotificationsSwitch').change(updateConfigUi);
$('#workingScheduleSwitch').change(updateConfigUi);
- $('#wifiSwitch').change(updateConfigUi);
$('#storageDeviceSelect').change(function () {
$('#rootDirectoryEntry').val('/');
/* motion notifications */
'motion_notifications': $('#motionNotificationsSwitch')[0].checked,
'motion_notifications_emails': $('#emailAddressesEntry').val(),
+ 'smtp_server': $('#smtpServerEntry').val(),
+ 'smtp_port': $('#smtpPortEntry').val(),
+ 'smtp_account': $('#smtpAccountEntry').val(),
+ 'smtp_password': $('#smtpPasswordEntry').val(),
+ 'smtp_tls': $('#smtpTlsSwitch')[0].checked,
/* working schedule */
'working_schedule': $('#workingScheduleSwitch')[0].checked,
/* motion notifications */
$('#motionNotificationsSwitch')[0].checked = dict['motion_notifications'];
$('#emailAddressesEntry').val(dict['motion_notifications_emails']);
-
+ $('#smtpServerEntry').val(dict['smtp_server']);
+ $('#smtpPortEntry').val(dict['smtp_port']);
+ $('#smtpAccountEntry').val(dict['smtp_account']);
+ $('#smtpPasswordEntry').val(dict['smtp_password']);
+ $('#smtpTlsSwitch')[0].checked = dict['smtp_tls'];
+
/* working schedule */
$('#workingScheduleSwitch')[0].checked = dict['working_schedule'];
$('#mondayFrom').val(dict['monday_from']);
</tr>
</table>
- <div class="settings-section-title hidden"><input type="checkbox" class="styled section notifications" id="motionNotificationsSwitch">Motion Notifications</div>
+ <div class="settings-section-title advanced-setting"><input type="checkbox" class="styled section notifications" id="motionNotificationsSwitch">Motion Notifications</div>
<table class="settings">
- <tr class="settings-item hidden">
+ <tr class="settings-item advanced-setting">
<td class="settings-item-label"><span class="settings-item-label">Email Addresses</span></td>
<td class="settings-item-value"><input type="text" class="styled notifications" id="emailAddressesEntry" placeholder="email addresses..."></td>
- <td><span class="help-mark" title="email addresses (separated by comma) that are added here will receive notifications whenever a motion event is detected (leave empty to disable email notifications)">?</span></td>
+ <td><span class="help-mark" title="email addresses (separated by comma) that are added here will receive notifications whenever a motion event is detected">?</span></td>
+ </tr>
+ <tr class="settings-item advanced-setting">
+ <td colspan="100"><div class="settings-item-separator"></div></td>
+ </tr>
+ <tr class="settings-item advanced-setting">
+ <td class="settings-item-label"><span class="settings-item-label">SMTP Server</span></td>
+ <td class="settings-item-value"><input type="text" class="styled notifications" id="smtpServerEntry" placeholder="e.g. smtp.gmail.com"></td>
+ <td><span class="help-mark" title="enter the hostname or IP address of your SMTP server (for Gmail use smtp.gmail.com)">?</span></td>
+ </tr>
+ <tr class="settings-item advanced-setting">
+ <td class="settings-item-label"><span class="settings-item-label">SMTP Port</span></td>
+ <td class="settings-item-value"><input type="text" class="styled number notifications" id="smtpPortEntry" placeholder="e.g. 587"></td>
+ <td><span class="help-mark" title="enter the port used by your SMTP server (usually 465 for non-TLS connections and 587 for TLS connections)">?</span></td>
+ </tr>
+ <tr class="settings-item advanced-setting">
+ <td class="settings-item-label"><span class="settings-item-label">SMTP Account</span></td>
+ <td class="settings-item-value"><input type="text" class="styled notifications" id="smtpAccountEntry" placeholder="account@gmail.com..."></td>
+ <td><span class="help-mark" title="enter your SMTP account (normally your email address)">?</span></td>
+ </tr>
+ <tr class="settings-item advanced-setting">
+ <td class="settings-item-label"><span class="settings-item-label">SMTP Password</span></td>
+ <td class="settings-item-value"><input type="password" class="styled notifications" id="smtpPasswordEntry"></td>
+ <td><span class="help-mark" title="enter your SMTP account password (for Gmail use your Google password or an app-specific generated password)">?</span></td>
+ </tr>
+ <tr class="settings-item advanced-setting">
+ <td class="settings-item-label"><span class="settings-item-label">Use TLS</span></td>
+ <td class="settings-item-value"><input type="checkbox" class="styled notifications" id="smtpTlsSwitch"></td>
+ <td><span class="help-mark" title="enable this if your SMTP server requires TLS (Gmail works either way)">?</span></td>
</tr>
</table>